一个基于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<stringstring> xmlNamespaces = new Dictionary<stringstring>();
     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<stringstring> xmlNamespaces = new Dictionary<stringstring>();
 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 


 

posted @ 2010-07-08 23:03  Dreampuf  阅读(2946)  评论(4编辑  收藏  举报