基于LINQ TO SQL的多层架构中,如何将实体附加至不同的DataContext
2013-08-02 16:54
393 查看
基于LINQ TO SQL的多层架构中,如何将实体附加至不同的DataContext
最近更新: 2013-2-19 | 124 | 0 |
1.本文中所提到的“实体”均为由LINQ TO SQL生成的(即.dbml)
2.你需要了解LINQ TO SQL对表关联的实现方式,EntitySet 和 EntityRef
也许你看到标题后,会觉得问题比较抽象,那么我举个实例来具体说明一下问题。
在基于LINQ TO SQL的N层架构中,假如我们需要对一个实体进行更新,那么流程应是这样:
流程
BLL.GetModel(p=>p.id==1) --> 修改相应属性(字段)值 --> BLL.Update(Entity entity) --> DAL.Update(Entity entity) --> 更新成功
此时,我们需要将这个实体从业务层(BLL)传递到数据访问层(DAL),当GetModel方法返回实体后 会立即释放掉DataContext,然后到了执行DAL.Update(Entity entity)方法时又重新实例化一个 DataContext来进行更新操作;可见被传递的实体是从第一个DataContext传递到另一个 DataContext,在 LINQ TO SQL中这种跨越不同DataContext操作时,需要先进行附加操作,也就是 context.Entity.Attach(entity,true); 最后再context.SubmitChanges();
还是看看代码吧:
class BLL { private readonly DAL dal = new DAL(); public LinqToSqlProvider.User GetModel (Expression> expression) { dal.GetModel(expression); } public void Update(LinqToSqlProvider.User entity) { dal.Update(entity); } } class DAL { public LinqToSqlProvider.User GetModel (Expression> expression) { LinqToSqlProvider.User entry = new CriTextBroadcast.LinqToSqlProvider.User(); using (CriTextBroadcastDBDataContext context = DataContext) { entry = context.User.SingleOrDefault(expression); } return entry; } public void Update(LinqToSqlProvider.User entity) { using (CriTextBroadcastDBDataContext context = DataContext) { context.User.Attach(entry, true); context.SubmitChanges(); } } }
实际我们用以上代码操作时,会出现此异常:
已尝试 Attach 或 Add 实体,该实体不是新实体,可能是从其他 DataContext 中加载来 的......
查了N多资料未果,后来还是在一国外的帖子里看到了类似问题。原来是这个实体对应的表有若干个关 联表,如:User -> Message ,User -> Images等,在生成实体类时会自动产生: EntitySet Message这样的属性,由于我们在获取实体时并未将这些关联的内容一起读出 来,而在附加时(Attach)这些属性便会出现ObjectDisposedException异常,也就是因为之前查询这个 实体时的DataContext已经释放掉了导致的。
解决方法:
///
/// 辅助LinqToSql实体与原DataContext分离 ///
/// /// public static void Detatch(TEntity entity) { Type t = entity.GetType(); System.Reflection.PropertyInfo[] properties = t.GetProperties (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var property in properties) { string name = property.Name; if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>)) { property.SetValue(entity, null, null); } } System.Reflection.FieldInfo[] fields = t.GetFields (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); foreach (var field in fields) { string name = field.Name; if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof (EntityRef<>)) { field.SetValue(entity, null); } } System.Reflection.EventInfo eventPropertyChanged = t.GetEvent ("PropertyChanged"); System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging"); if (eventPropertyChanged != null) { eventPropertyChanged.RemoveEventHandler(entity, null); } if (eventPropertyChanging != null) { eventPropertyChanging.RemoveEventHandler(entity, null); } }
应在获得实体后使用Detach(entity)方法将实体与原DataContext分离,然后再附加(Attach)到新的 DataContext中去
相关文章推荐
- Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 【转】一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- LinqToSql--DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 【转】一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- DLINQ(LINQ to SQL)之用户自定义函数、在不同的DataContext之间做更新、缓存、获取信息、数据加载选项和延迟加载
- Linq to sql(二):DataContext与实体
- Linq to sql(二):DataContext与实体
- Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体
- 一步一步学Linq to sql(二):DataContext与实体