最近用ado.net entity framework遇到了和NHibernate上相同的问题:
1、open session in view如果entity的objectcontext在dao层关闭的话,在其他层访问lazy-load的属性就会出错,这都是因为上下文已经关闭的缘故,当然过早关闭上下文还会造成(1)在一次访问中多个DAO频繁的新建objectcontext造成不必要的麻烦;2、在更新或者删除时经常要为把从其他dao上下文里获取的数据附加到当前上下文这样极度繁琐的操作。(N)Hibernate做为一个老牌的orm框架通过引入open session in view的方式避免上述问题,使得一次访问多个dao只使用一个session,而且把关闭的操作放在一次http访问的最后时间进行,也就是建个httpmodule在beginrequset事件时新建session,并在endrequest事件时提交事务并关闭,这样就可以实现透明的持久化和lzay-load。
由于ado.net entity framework和NHibernate很相似,所以可以借鉴NHibernate的处理方式实现一个ado.net entity framework版的open session in view,代码如下。
首先实现一个从httpcontext上下文中获取objectcontext的help类
EntityHelp
1 public class EntityHelp
2 {
3 public static JobSnsEntities GetEntity()
4 {
5 JobSnsEntities entity;
6 if (HttpContext.Current.Items["Entity"] == null)
7 {
8 entity = new JobSnsEntities();
9 HttpContext.Current.Items.Add("Entity", entity);
10 }
11 else
12 {
13 entity = HttpContext.Current.Items["Entity"] as JobSnsEntities;
14 }
15 return entity;
16 }
17 }
实现ihttpmodule
OSIVHttpModule
1 public class OSIVHttpModule:IHttpModule
2 {
3 #region IHttpModule 成员
4
5 public void Dispose()
6 {
7 throw new NotImplementedException();
8 }
9
10 public void Init(HttpApplication context)
11 {
12 context.BeginRequest += new EventHandler(context_BeginRequest);
13 context.EndRequest += new EventHandler(context_EndRequest);
14 }
15
16 void context_EndRequest(object sender, EventArgs e)
17 {
18 JobSnsEntities entity = HttpContext.Current.Items["Entity"] as JobSnsEntities;
19 if (entity != null)
20 {
21 entity.SaveChanges();
22 entity.Dispose();
23 }
24 }
25
26 void context_BeginRequest(object sender, EventArgs e)
27 {
28 if (HttpContext.Current.Items["Entity"] == null)
29 {
30 HttpContext.Current.Items.Add("Entity", new JobSnsEntities());
31 }
32 }
33
34 #endregion
35 }
这样只要在dao中从help中获取objectcontext,我们进行完操作后不须显示的关闭。
2、范型DAO
在使用NHibernate时,范型DAO是个常用的省事技巧,将基础的crud写在范型DAO中,其他DAO只要去继承它,就可以公用一套crud方法,这在NHibernate中是很容易实现的,不过由于entity frameword比较笨拙,实现比起NHibernate要难看一些,代码如下
1public class GenericEFDao<Context,T> where Context:ObjectContext where T : class
2 {
3 private Context _db = EntityHelp.GetEntity() as Context;
4 public Context db
5 {
6 get { return _db; }
7 }
8
9
10 CRUD#region CRUD
11 /**//// <summary>
12 /// 通过id查找
13 /// </summary>
14 /// <param name="id"></param>
15 /// <returns></returns>
16 public virtual T FindById(object id)
17 {
18 string str = String.Format("select value t from {0} as t where t.{1}=@name",
19 new object[] { GetClassType().Name, GetPrimaryKey().Name });
20 ObjectQuery<T> query = db.CreateQuery<T>(str, new ObjectParameter[] { new ObjectParameter("name", id) });
21 return query.FirstOrDefault();
22 }
23 /**//// <summary>
24 /// 查找所有
25 /// </summary>
26 /// <returns></returns>
27 public virtual List<T> FindAll()
28 {
29 ObjectQuery<T> query = db.CreateQuery<T>("[" + typeof(T).Name + "]");
30 return query.ToList();
31 }
32
33 /**//// <summary>
34 /// 插入数据,并且提交变更
35 /// </summary>
36 /// <param name="item"></param>
37 /// <returns></returns>
38 public virtual T Save(T item)
39 {
40 return Save(item, true);
41 }
42
43 /**//// <summary>
44 /// 插入数据
45 /// </summary>
46 /// <param name="item"></param>
47 /// <param name="submitChanges">是否提交变更</param>
48 /// <returns></returns>
49 public virtual T Save(T item, bool submitChanges)
50 {
51 db.AddObject(typeof(T).Name, item);
52 if (submitChanges)
53 db.SaveChanges();
54 return item;
55 }
56 /**//// <summary>
57 /// 删除数据,默认提交
58 /// </summary>
59 /// <param name="item"></param>
60 public virtual void Delete(T item)
61 {
62 Delete(item, true);
63 }
64 /**//// <summary>
65 /// 删除数据
66 /// </summary>
67 /// <param name="item"></param>
68 /// <param name="submitChanges">是否提交</param>
69 public virtual void Delete(T item, bool submitChanges)
70 {
71 db.DeleteObject(item);
72 if (submitChanges)
73 db.SaveChanges();
74 }
75 /**//// <summary>
76 /// 更新
77 /// </summary>
78 public virtual void UpdateChanges()
79 {
80 db.SaveChanges();
81 }
82
83 #endregion
84
85 help#region help
86 /**//// <summary>
87 /// 获取主键
88 /// </summary>
89 /// <returns></returns>
90 private PropertyInfo GetPrimaryKey()
91 {
92 PropertyInfo primaryKey = null;
93 foreach (var a in GetClassType().GetProperties())
94 {
95 foreach (EdmScalarPropertyAttribute c in a.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false))
96 {
97 if (c.EntityKeyProperty)
98 {
99 primaryKey = a;
100 }
101 }
102
103 }
104 return primaryKey;
105 }
106 /**//// <summary>
107 /// 获取type
108 /// </summary>
109 /// <returns></returns>
110 private Type GetClassType()
111 {
112 return typeof(T);
113 }
114 #endregion
由于entity framework和NHibernate的相似性,我们可以把NHibernate中的最佳实践嫁接过来,使得在使用ado.net entity framework能够得心应手,不过由于项目还没完成,对于这样使用是否会发生 淮橘为枳的问题现在还是未可知的,只有等到系统上线的时候才能知道。