一个基于EntityFramework的DAO (反射出架构信息并应用在CRUD中)
满是坎坷的完成了这个DAO,间或断了几次,对MSDN欲求不满,还好Google在.
在VS中生成了映射文件,以及实体类后,简单配置一下就可以使用了,请各位指点迷津,这样写法是否妥当,千万别把这个类拿去搞生产,否则后果自负,作者不承担任何后果.
我们知道,一般的项目都是分了几层,而其中少不了对于数据持久化的管理,也就是数据访问层,在被Hibernate的配置淹没后,被DbEntry.net(国产推荐!)的总总不适后又投向了M$自己的EntityFramework,但是也不能直接拿来用,万一以后又要转向其他数据源,那改动就真的是欲哭无泪了.所以免不了对其封装一番.好在C#是一门相当灵活的语言,通过反射,我们可以进行对程序自己的解析.下面我就将我对EF简单封装后的一个DAO以及一些体会和大家分享,经验不足难免有误人子弟的嫌疑,欢迎各位指正.
- 如何获得实体类的映射信息
在EF映射信息生成后编译,然后在使用项目中引用,反射得到映射资源,一般是个目录下,怎样得知映射文件名?在EF连接字符串中可以获得.在metadata节点可获得.metadata=res://*/School.csdl|res://*/School.ssdl|res://*/School.msl; 如何读取映射信息
通过XML操作可以获得,不过在这里我碰到了个问题,就是有名称空间的节点以及属性该如何访问,试了几次,以为Xpath没写对,结果参照XPathVisualizer(一个开源项目,用于验证Xpath)显示结果是正确的,后来在其源码中找到了读取有名称空间的节点以及属性的方法,大致思路就是获得所有名称空间并在检索xpath时提供这些名称空间.1 private XmlNamespaceManager getAllNamespace(XmlDocument doc)
2 {
3 XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
4 XPathNavigator nav = doc.CreateNavigator();
5 XPathNodeIterator list = nav.Select("//namespace::*[name() != 'xml'][not(http://www.cnblogs.com/namespace::*=.)]");
6 Dictionary<string, string> xmlNamespaces = new Dictionary<string, string>();
7 int c = 1;
8 while (list.MoveNext())
9 {
10 XPathNavigator nsNode = list.Current;
11 if (nsNode.NodeType == XPathNodeType.Namespace)
12 {
13 string ns = nsNode.Value;
14 if (!xmlNamespaces.Values.Contains(ns))
15 {
16 // get the prefix - it's either empty or not
17 string origPrefix = nsNode.LocalName;
18
19 // make sure the prefix is unique
20 int dupes = 0;
21 string actualPrefix = origPrefix;
22 while (actualPrefix == "" || xmlNamespaces.Keys.Contains(actualPrefix))
23 {
24 actualPrefix = (origPrefix == "")
25 ? String.Format("ns{0}", c++)
26 : String.Format("{0}-{1}", origPrefix, dupes++);
27 }
28 xnm.AddNamespace(actualPrefix, ns);
29 xmlNamespaces.Add(actualPrefix, ns);
30 }
31
32 }
33 }
34 return xnm;
35 }"it"别名
在EF构造SQL语句的时候,使用的是"it"作为默认别名,所以在进行SQL操作的时候记得要加上"it."作为前缀.读取出数据后记得移除读取对象与ObjectContext的联系
仅仅只是toList返回对象后还要为每个对象Detach,解除绑定才能进行一些后续操作,否则无法再次访问数据库(当然,除非是在同一个ObjectContext下)- 修改
修改的时候如果不是同一ObjectContext读取的,那么还需要使用该上下文来读取出对象,否者会报错.详细的讨论:http://social.msdn.microsoft.com/Forums/en-SG/adodotnetentityframework/thread/501d7b99-0cb9-44b6-b2cd-16275a151b31
全部代码
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 using System.Configuration;
7 using System.Data.Objects;
8 using System.Data.EntityClient;
9 using System.Xml;
10 using System.Xml.XPath;
11 namespace ES.DAL
12 {
13 public class DataService<T>
14 where T : System.Data.Objects.DataClasses.EntityObject
15 {
16 private static Type contextType;
17 private static XmlDocument doc;
18 private static string entityContainer;
19
20 private string tableName;
21 private string keyName;
22 private Dictionary<string, Type> propertype;
23
24 static DataService()
25 {
26 contextType = Type.GetType(ConfigurationManager.ConnectionStrings[DataService.EFObjectContext].ConnectionString);
27
28 EntityConnectionStringBuilder scsb = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings[DataService.ConnectionString].ConnectionString);
29 string str = scsb.Metadata.Split('|').Single(x => x.EndsWith(".csdl"));
30 var ls = contextType.Assembly.GetManifestResourceStream(str.Substring(str.LastIndexOf('/') + 1));
31 using (System.IO.StreamReader reader = new System.IO.StreamReader(ls))
32 {
33 string csdlData = reader.ReadToEnd();
34 doc = new XmlDocument();
35 doc.LoadXml(csdlData);
36 }
37 }
38
39 private ObjectContext getInstence()
40 {
41 return (ObjectContext)Activator.CreateInstance(contextType);
42 }
43
44 private XmlNamespaceManager getAllNamespace(XmlDocument doc)
45 {
46 XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
47 XPathNavigator nav = doc.CreateNavigator();
48 XPathNodeIterator list = nav.Select("//namespace::*[name() != 'xml'][not(http://www.cnblogs.com/namespace::*=.)]");
49 Dictionary<string, string> xmlNamespaces = new Dictionary<string, string>();
50 int c = 1;
51 while (list.MoveNext())
52 {
53 XPathNavigator nsNode = list.Current;
54 if (nsNode.NodeType == XPathNodeType.Namespace)
55 {
56 string ns = nsNode.Value;
57 if (!xmlNamespaces.Values.Contains(ns))
58 {
59 // get the prefix - it's either empty or not
60 string origPrefix = nsNode.LocalName;
61
62 // make sure the prefix is unique
63 int dupes = 0;
64 string actualPrefix = origPrefix;
65 while (actualPrefix == "" || xmlNamespaces.Keys.Contains(actualPrefix))
66 {
67 actualPrefix = (origPrefix == "")
68 ? String.Format("ns{0}", c++)
69 : String.Format("{0}-{1}", origPrefix, dupes++);
70 }
71 xnm.AddNamespace(actualPrefix, ns);
72 xmlNamespaces.Add(actualPrefix, ns);
73 }
74
75 }
76 }
77 return xnm;
78 }
79 public DataService()
80 {
81 tableName = typeof(T).Name;
82 XmlNamespaceManager xnm = getAllNamespace(doc);
83 entityContainer = doc.SelectSingleNode(".//ns1:EntityContainer", xnm).Attributes["Name"].Value;
84 var cur = doc.SelectSingleNode("//ns1:EntityType[@Name=\"" + tableName + "\"]", xnm);
85 XmlNodeList pros = cur.SelectNodes(".//ns1:Property", xnm);
86 propertype = new Dictionary<string, Type>();
87 for (int i = 0; i < pros.Count; i++)
88 {
89 XmlNode node = pros[i];
90
91 //System.Collections.IEnumerator itor = node.Attributes.GetEnumerator();
92 //while (itor.MoveNext())
93 //{
94 // XmlAttribute a = (XmlAttribute)itor.Current;
95
96 //}
97
98 if (node.Attributes["StoreGeneratedPattern", xnm.LookupNamespace("annotation")] != null)
99 keyName = node.Attributes["Name"].Value;
100 propertype.Add(node.Attributes["Name"].Value, Type.GetType(node.Attributes["Type"].Value));
101 }
102 }
103 /// <summary>
104 /// 执行Linq表达式返回List
105 /// </summary>
106 /// <param name="linq">接受一个QbjectQuery,返回IEnumerable的表达式</param>
107 /// <returns>List</returns>
108 public List<T> Linq(Func<ObjectQuery<T>, IEnumerable<T>> linq)
109 {
110 using(var context = getInstence())
111 {
112 return linq(context.CreateQuery<T>("[" + tableName + "]")).ToList<T>();
113 }
114 }
115 public List<T1> Linq<T1>(Func<ObjectQuery<T>, IEnumerable<T1>> linq)
116 {
117 using (var context = getInstence())
118 {
119 return linq(context.CreateQuery<T>("[" + tableName + "]")).ToList<T1>();
120 }
121 }
122
123 public T FindById(object keyValue)
124 {
125 var key = new System.Data.EntityKey(entityContainer + "." + tableName, keyName, keyValue);
126 using (var context = getInstence())
127 {
128 T result = (T)context.GetObjectByKey(key);
129 context.Detach(result);
130 return result;
131 }
132 }
133
134 public List<T> Find()
135 {
136 return Find(0, -1, x => true, keyName, false);
137 }
138 public List<T> Find(Func<T, bool> wherecase)
139 {
140 return Find(0, -1, wherecase, keyName, false);
141 }
142 public List<T> Find(Func<T, bool> wherecase, bool isdescending)
143 {
144 return Find(0, -1, wherecase, keyName, isdescending);
145 }
146 public List<T> Find(int start, int len)
147 {
148 return Find(start, len, null, keyName, false);
149 }
150 public List<T> Find(int start, int len, Func<T, bool> wherecase)
151 {
152 return Find(start, len, wherecase, keyName, false);
153 }
154 public List<T> Find(int start, int len, Func<T, bool> wherecase, string orderKey)
155 {
156 return Find(start, len, wherecase, orderKey, false);
157 }
158 public List<T> Find(int start, int len, Func<T, bool> wherecase, string orderKey, bool isdescending)
159 {
160 using (var context = getInstence())
161 {
162 ObjectQuery<T> query = context.CreateQuery<T>("[" + tableName + "]").OrderBy(orderKey);
163 orderKey = orderKey.StartsWith("it.") ? orderKey : "it." + orderKey;
164 IEnumerable<T> result;
165 if (wherecase != null)
166 result = query.Where(wherecase);
167 else
168 result = query.AsEnumerable();
169 result = result.Skip(start);
170 result = len == -1 ?
171 isdescending ?
172 result.Reverse()
173 :
174 result
175 :
176 isdescending ?
177 result.Take(len).Reverse()
178 :
179 result.Take(len);
180 List<T> list = result.ToList();
181 list.ForEach(x => context.Detach(x));
182 return list;
183 }
184 }
185
186 public void Save(T o)
187 {
188 using (var context = getInstence())
189 {
190 context.AddObject(tableName, o);
191 context.SaveChanges();
192 }
193 }
194 public void Save(IEnumerable<T> listo)
195 {
196 using (var context = getInstence())
197 {
198 foreach (T i in listo)
199 {
200 context.AddObject(tableName, i);
201 }
202 context.SaveChanges();
203 }
204 }
205 public void Update(T o)
206 {
207 using (var context = getInstence())
208 {
209 //fix
210 //http://social.msdn.microsoft.com/Forums/en-SG/adodotnetentityframework/thread/501d7b99-0cb9-44b6-b2cd-16275a151b31
211 object original = context.GetObjectByKey(o.EntityKey);
212 context.ApplyPropertyChanges(tableName, o);
213 context.SaveChanges();
214 }
215 }
216 public void Update(IEnumerable<T> listo)
217 {
218 using (var context = getInstence())
219 {
220 foreach (T o in listo)
221 {
222 object original = context.GetObjectByKey(o.EntityKey);
223 context.ApplyPropertyChanges(tableName, o);
224 }
225 context.SaveChanges();
226 }
227 }
228 public void Delete(T o)
229 {
230 using (var context = getInstence())
231 {
232 object original = context.GetObjectByKey(o.EntityKey);
233 context.DeleteObject(o);
234 context.SaveChanges();
235 }
236 }
237 public void Delete(IEnumerable<T> listo)
238 {
239 using (var context = getInstence())
240 {
241 foreach (T o in listo)
242 {
243 object original = context.GetObjectByKey(o.EntityKey);
244 context.DeleteObject(o);
245 }
246 context.SaveChanges();
247 }
248 }
249
250 }
251
252 public class DataService
253 {
254 /// <summary>
255 /// 设置从配置文件中读取的ObjectContext节点\n默认为"EFObjectContext"
256 /// </summary>
257 public static string EFObjectContext = "EFObjectContext";
258 /// <summary>
259 /// 设置从配置文件中读取的EF链接节点\n默认为"ConnectionString"
260 /// </summary>
261 public static string ConnectionString = "ConnectionString";
262 }
263
264 }
265
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 using System.Configuration;
7 using System.Data.Objects;
8 using System.Data.EntityClient;
9 using System.Xml;
10 using System.Xml.XPath;
11 namespace ES.DAL
12 {
13 public class DataService<T>
14 where T : System.Data.Objects.DataClasses.EntityObject
15 {
16 private static Type contextType;
17 private static XmlDocument doc;
18 private static string entityContainer;
19
20 private string tableName;
21 private string keyName;
22 private Dictionary<string, Type> propertype;
23
24 static DataService()
25 {
26 contextType = Type.GetType(ConfigurationManager.ConnectionStrings[DataService.EFObjectContext].ConnectionString);
27
28 EntityConnectionStringBuilder scsb = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings[DataService.ConnectionString].ConnectionString);
29 string str = scsb.Metadata.Split('|').Single(x => x.EndsWith(".csdl"));
30 var ls = contextType.Assembly.GetManifestResourceStream(str.Substring(str.LastIndexOf('/') + 1));
31 using (System.IO.StreamReader reader = new System.IO.StreamReader(ls))
32 {
33 string csdlData = reader.ReadToEnd();
34 doc = new XmlDocument();
35 doc.LoadXml(csdlData);
36 }
37 }
38
39 private ObjectContext getInstence()
40 {
41 return (ObjectContext)Activator.CreateInstance(contextType);
42 }
43
44 private XmlNamespaceManager getAllNamespace(XmlDocument doc)
45 {
46 XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
47 XPathNavigator nav = doc.CreateNavigator();
48 XPathNodeIterator list = nav.Select("//namespace::*[name() != 'xml'][not(http://www.cnblogs.com/namespace::*=.)]");
49 Dictionary<string, string> xmlNamespaces = new Dictionary<string, string>();
50 int c = 1;
51 while (list.MoveNext())
52 {
53 XPathNavigator nsNode = list.Current;
54 if (nsNode.NodeType == XPathNodeType.Namespace)
55 {
56 string ns = nsNode.Value;
57 if (!xmlNamespaces.Values.Contains(ns))
58 {
59 // get the prefix - it's either empty or not
60 string origPrefix = nsNode.LocalName;
61
62 // make sure the prefix is unique
63 int dupes = 0;
64 string actualPrefix = origPrefix;
65 while (actualPrefix == "" || xmlNamespaces.Keys.Contains(actualPrefix))
66 {
67 actualPrefix = (origPrefix == "")
68 ? String.Format("ns{0}", c++)
69 : String.Format("{0}-{1}", origPrefix, dupes++);
70 }
71 xnm.AddNamespace(actualPrefix, ns);
72 xmlNamespaces.Add(actualPrefix, ns);
73 }
74
75 }
76 }
77 return xnm;
78 }
79 public DataService()
80 {
81 tableName = typeof(T).Name;
82 XmlNamespaceManager xnm = getAllNamespace(doc);
83 entityContainer = doc.SelectSingleNode(".//ns1:EntityContainer", xnm).Attributes["Name"].Value;
84 var cur = doc.SelectSingleNode("//ns1:EntityType[@Name=\"" + tableName + "\"]", xnm);
85 XmlNodeList pros = cur.SelectNodes(".//ns1:Property", xnm);
86 propertype = new Dictionary<string, Type>();
87 for (int i = 0; i < pros.Count; i++)
88 {
89 XmlNode node = pros[i];
90
91 //System.Collections.IEnumerator itor = node.Attributes.GetEnumerator();
92 //while (itor.MoveNext())
93 //{
94 // XmlAttribute a = (XmlAttribute)itor.Current;
95
96 //}
97
98 if (node.Attributes["StoreGeneratedPattern", xnm.LookupNamespace("annotation")] != null)
99 keyName = node.Attributes["Name"].Value;
100 propertype.Add(node.Attributes["Name"].Value, Type.GetType(node.Attributes["Type"].Value));
101 }
102 }
103 /// <summary>
104 /// 执行Linq表达式返回List
105 /// </summary>
106 /// <param name="linq">接受一个QbjectQuery,返回IEnumerable的表达式</param>
107 /// <returns>List</returns>
108 public List<T> Linq(Func<ObjectQuery<T>, IEnumerable<T>> linq)
109 {
110 using(var context = getInstence())
111 {
112 return linq(context.CreateQuery<T>("[" + tableName + "]")).ToList<T>();
113 }
114 }
115 public List<T1> Linq<T1>(Func<ObjectQuery<T>, IEnumerable<T1>> linq)
116 {
117 using (var context = getInstence())
118 {
119 return linq(context.CreateQuery<T>("[" + tableName + "]")).ToList<T1>();
120 }
121 }
122
123 public T FindById(object keyValue)
124 {
125 var key = new System.Data.EntityKey(entityContainer + "." + tableName, keyName, keyValue);
126 using (var context = getInstence())
127 {
128 T result = (T)context.GetObjectByKey(key);
129 context.Detach(result);
130 return result;
131 }
132 }
133
134 public List<T> Find()
135 {
136 return Find(0, -1, x => true, keyName, false);
137 }
138 public List<T> Find(Func<T, bool> wherecase)
139 {
140 return Find(0, -1, wherecase, keyName, false);
141 }
142 public List<T> Find(Func<T, bool> wherecase, bool isdescending)
143 {
144 return Find(0, -1, wherecase, keyName, isdescending);
145 }
146 public List<T> Find(int start, int len)
147 {
148 return Find(start, len, null, keyName, false);
149 }
150 public List<T> Find(int start, int len, Func<T, bool> wherecase)
151 {
152 return Find(start, len, wherecase, keyName, false);
153 }
154 public List<T> Find(int start, int len, Func<T, bool> wherecase, string orderKey)
155 {
156 return Find(start, len, wherecase, orderKey, false);
157 }
158 public List<T> Find(int start, int len, Func<T, bool> wherecase, string orderKey, bool isdescending)
159 {
160 using (var context = getInstence())
161 {
162 ObjectQuery<T> query = context.CreateQuery<T>("[" + tableName + "]").OrderBy(orderKey);
163 orderKey = orderKey.StartsWith("it.") ? orderKey : "it." + orderKey;
164 IEnumerable<T> result;
165 if (wherecase != null)
166 result = query.Where(wherecase);
167 else
168 result = query.AsEnumerable();
169 result = result.Skip(start);
170 result = len == -1 ?
171 isdescending ?
172 result.Reverse()
173 :
174 result
175 :
176 isdescending ?
177 result.Take(len).Reverse()
178 :
179 result.Take(len);
180 List<T> list = result.ToList();
181 list.ForEach(x => context.Detach(x));
182 return list;
183 }
184 }
185
186 public void Save(T o)
187 {
188 using (var context = getInstence())
189 {
190 context.AddObject(tableName, o);
191 context.SaveChanges();
192 }
193 }
194 public void Save(IEnumerable<T> listo)
195 {
196 using (var context = getInstence())
197 {
198 foreach (T i in listo)
199 {
200 context.AddObject(tableName, i);
201 }
202 context.SaveChanges();
203 }
204 }
205 public void Update(T o)
206 {
207 using (var context = getInstence())
208 {
209 //fix
210 //http://social.msdn.microsoft.com/Forums/en-SG/adodotnetentityframework/thread/501d7b99-0cb9-44b6-b2cd-16275a151b31
211 object original = context.GetObjectByKey(o.EntityKey);
212 context.ApplyPropertyChanges(tableName, o);
213 context.SaveChanges();
214 }
215 }
216 public void Update(IEnumerable<T> listo)
217 {
218 using (var context = getInstence())
219 {
220 foreach (T o in listo)
221 {
222 object original = context.GetObjectByKey(o.EntityKey);
223 context.ApplyPropertyChanges(tableName, o);
224 }
225 context.SaveChanges();
226 }
227 }
228 public void Delete(T o)
229 {
230 using (var context = getInstence())
231 {
232 object original = context.GetObjectByKey(o.EntityKey);
233 context.DeleteObject(o);
234 context.SaveChanges();
235 }
236 }
237 public void Delete(IEnumerable<T> listo)
238 {
239 using (var context = getInstence())
240 {
241 foreach (T o in listo)
242 {
243 object original = context.GetObjectByKey(o.EntityKey);
244 context.DeleteObject(o);
245 }
246 context.SaveChanges();
247 }
248 }
249
250 }
251
252 public class DataService
253 {
254 /// <summary>
255 /// 设置从配置文件中读取的ObjectContext节点\n默认为"EFObjectContext"
256 /// </summary>
257 public static string EFObjectContext = "EFObjectContext";
258 /// <summary>
259 /// 设置从配置文件中读取的EF链接节点\n默认为"ConnectionString"
260 /// </summary>
261 public static string ConnectionString = "ConnectionString";
262 }
263
264 }
265