WEB开发网
开发学院WEB开发ASP 【分享】基于LINQ TO SQL的多层架构中,如何将实体... 阅读

【分享】基于LINQ TO SQL的多层架构中,如何将实体附加至不同的DataContext

 2010-01-21 10:44:29 来源:WEB开发网   
核心提示:注意: 1.本文中所提到的“实体”均为由LINQ TO SQL生成的(即.dbml) 2.你需要了解LINQ TO SQL对表关联的实现方式,EntitySet 和 EntityRef 也许你看到标题后,【分享】基于LINQ TO SQL的多层架构中,如何将实体附加至不同的DataContext,会觉得问题比较抽象,那
注意:

   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<Func<LinqToSqlProvider.User, bool>> expression)
{
  dal.GetModel(expression);
}
 public void Update(LinqToSqlProvider.User entity)
 {
   dal.Update(entity);
 }
}

class DAL
{
    
    public LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> 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> Message这样的属性,由于我们在获取实体时并未将这些关联的内容一起读出来,而在附加时(Attach)这些属性便会出现ObjectDisposedException异常,也就是因为之前查询这个实体时的DataContext已经释放掉了导致的。



解决方法:



代码
/// <summary>
    /// 辅助LinqToSql实体与原DataContext分离
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    public static void Detatch<TEntity>(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中去

Tags:分享 基于 LINQ

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接