当前位置: 代码迷 >> C# >> EF底层封装了之后多表操作的有关问题
  详细解决方案

EF底层封装了之后多表操作的有关问题

热度:348   发布时间:2016-04-28 08:38:53.0
EF底层封装了之后多表操作的问题
DAL底层封装了一个上下文的文件源码:

public abstract class EFContext
{
  #region 单例模式创建一个上下文对象
  private static DbContext dbContext=null;
  
  protected static DbContext CreateInstance(string connectKeyName="DbContext")
  {
    DbContext db=CallContext.GetData(connectKeyName) as DbContext;
    
    if(db==null)
    {
      db=Activator.CreateInstance(Type.GetType("AssemblyName."+connectKeyName+",AssemblyName")) as DbContext;
      CallContext.SetData(connectKeyName,db);
    }
    
    return db;
  }
  #endregion
  
  public DbContext _db=CreateInstance();
  
  public virtual int SaveChanges()
  {
    return this._db.SaveChanges();
  }
}



然后有一个IBaseRepository基接口定义了一些基础方法

public interface IBaseRepository<T> where T : class
{
  T Insert(T entity);
  void Delete(T entity);
  T Update(T entity);  
  //......
}


实现接口的一个文件DataAccess

public class DataAccess<T>:EFContext,IBaseRepository<T>,IDisposable where T: class
{
  public DataAccess(string connectKeyName)
  {
    _db.CreateInstance(!string.IsNullOrEmpty(connectKeyName)?connectKeyName:"DbContext");
  }
  
  public T Insert(T entity)
  {
    _db.Set<T>().Add(entity);
    return entity;
  }
  
  //......
}


上面是DAL的处理


下面开始BLL层的处理

public abstract class BaseRepository<T> : IBLL.IBaseRepository<T> where T : class
{
  private static string KeyName="DbContext";
  
  public static string SetConnectorName(string ckeyName="DbContext")
  {
    KeyName=ckeyName;
    return KeyName
  }
  

 public int SaveChanges()
 {
    return _baseRepository.SaveChanges();
 }
}
  
  private static IDAL.IBaseRepository<T> _baseRepository=new DAL.DataAccess<T>(KeyName);
  
  public T Update(T entity)
  {
    return _baseRepository.Update(entity);
  }
  
  //...集成IBLL.IBaseRepository接口的方法实现就不一一写了

}


每个表对应的BLL层的类文件


public class TableA : BaseRepository<Model.TableA>,IBLL.ITableA
{
  public TableA()
  {
    SetConnectorName("DbContext");
  }
}







后面有一个比较复杂的逻辑,就是有一个表A是作为主表,B,C分别是外键表,A中的字段分别是作为外键约束引用的B,C的主键,这样我在更新A,B,C的数据的时候我的操作就是直接更新A,然后把B,C中的当前数据的列表先执行删除,然后再插入到B,C中,写入如下

public int UpdateEntity(Model.TableA entity)
{
  var bList=entity.B==null?new List<Model.TableB>():entity.B.ToList();
  var cList=entity.C==null?new List<Model.TableC>():entity.C.ToList();
  entity.B=null;
  entity.C=null;
  IBLL.TableB tb=new BLL.TableB();
  IBLL.TableC tc=new BLL.TableC();
  tb.DeleteList(t=>t.aId==entity.Id);
  tc.DeleteList(t=>t.aId==entity.Id);
  base.Update(entity);
  if(bList.count!=0)
  {
    tb.InsertList(bList);
  }
  if(cList.Count!=0)
  {
    tc.InsertList(cList);
  }
  SaveChanges();
  tb.SaveChanges();//开始没有如下两句
  tc.SaveChanges();//开始没有如下两句
}


最开始的情况就是A表能够保存修改,但是B,C表的修改不能够被保存,后面加入了两句saveChanges就正常了,这个saveChanges方法不是保存的上下文吗,而我底层DAL.DataAccess获取DbContext时不是同一个导致吗,高人能告知下这是为什么吗?
------解决思路----------------------
博客园不是在外面又套了一个,什么IUnitOfWork,也就是他们自己也承认什么IRepository其实还不够,所以在套个IUnitOfWork去补充
------解决思路----------------------
看看开源项目:nopCommerce
你会更加好地运用nopCommerce模式


public class DataAccess<T>:EFContext,IBaseRepository<T>,IDisposable where T: class
{
  public DataAccess(string connectKeyName)
  {
    _db.CreateInstance(!string.IsNullOrEmpty(connectKeyName)?connectKeyName:"DbContext");
  }
   
  public T Insert(T entity)
  {
    _db.Set<T>().Add(entity);// 这里是_db, 你的单例变量是:private static DbContext dbContext=null;构造出来都没有用
    return entity;
  }
   
  //......
}
所以要分别savechange,另外 EF最好不要用单例

看看我推荐的项目IOC控制EF生命周期的方式

另外IUnitOfWork 还是一个不错的概念的,就看你自己怎么实现
  相关解决方案