繁体   English   中英

抽象实体框架

[英]Abstract Entity Framework

我想在实体框架和应用程序的其余部分之间创建一个抽象层。 但是我在使用实体框架时遇到了一些问题。

基本上(我也没有向您展示我创建的所有接口层),我将应用程序划分为几个项目,如下所示:

    • 包含我的域对象,这是我的数据存储对象的抽象
  1. DAL
    • 在我的数据存储和业务层之间创建一个链接。 包含两种类型的元素:
      • 私有的:我的EDMX,我的数据库对象以及一些其他生成的对象,为我提供了一些有用的方法,例如ToDomain / ToEntity
      • 公开的:我的数据访问对象,提供CRUD方法
  2. 商业
    • 包含我的应用程序的逻辑。 仅了解DAL和域层的公共元素。
  3. 介绍
    • 为用户显示域对象。 只知道业务层。

就像我说的那样,我想创建我的数据存储对象(在我的情况下是Database对象)的抽象,但是我想要一个适用于文件或WCF存储的解决方案,这样我的业务层对DAL一无所知实现。

这是我在DAL中所做的一瞥:

public abstract class GenericDao<TEntity, TDomain, TDbContext> : IGenericDao<TDomain>
    where TDbContext : DbContext, new()
    where TEntity : class
    where TDomain : class
{
    protected TDbContext _context;
    protected DbSet<TEntity> _dbSet;

    public GenericDao(TDbContext dbContext)
    {
        this._context = dbContext;
        this._dbSet = dbContext.Set<TEntity>();
    }

    public TDomain Create()
    {
        return this.ToDomain(this._dbSet.Create());
    } 

    public IList<TDomain> GetAll()
    {
        return this._dbSet.ToList().Select(entity => this.ToDomain(entity)).ToList();
    }

    public void Update(TDomain domain)
    {
        var entity = this.ToEntity(domain);

        var entry = this._context.Entry(entity);

        entry.State = EntityState.Modified;
    }

    public void Remove(TDomain domain)
    {
        _dbSet.Remove(this.ToEntity(domain));
    }

    protected abstract TDomain ToDomain(TEntity entity);

    protected abstract TEntity ToEntity(TDomain domain);
}

通过阅读代码,您可能会发现我的代码有什么问题:当我尝试删除或更新实体时,我没有在操纵连接到Entity Framework的实体。 如果我尝试将我的实体附加到dbContext ,它将失败,因为上下文中已经存在一个具有相同ID的实体。

我已经考虑过几种解决方案,但是没有一个能让我满意。

也许我的方法做错了什么? 我对存储库和DAO模式有些困惑(我读了任何东西,关于互联网上的区别却截然相反)。

您有两种选择:

  1. 为每个操作初始化新的dbcontext ,并在操作结束时将其处置:

     public abstract class GenericDao<TEntity, TDomain, TDbContext> : IGenericDao<TDomain> where TDbContext : DbContext, new() where TEntity : class where TDomain : class { protected Func<TDbContext> _contextFactory; public GenericDao(Func<TDbContext> contextFactory) { _contextFactory = contextFactory; } public TDomain Create() { using(var context = _contextFactory()) { return context.Set<TEntity>().Create(); } } public IList<TDomain> GetAll() { using(var context = _contextFactory()) { return context.Set<TEntity>().ToList() .Select(entity => this.ToDomain(entity)).ToList(); } } public void Update(TDomain domain) { using(var context = _contextFactory()) { var entity = this.ToEntity(domain); context.Attach(entity); var entry = this._context.Entry(entity); entry.State = EntityState.Modified; context.SaveChanges(); } } public void Remove(TDomain domain) { using(var context = _contextFactory()) { var entity = this.ToEntity(domain); context.Attach(entity); context.Set<TEntity>.Remove(entity); context.SaveChanges(); } } protected abstract TDomain ToDomain(TEntity entity); protected abstract TEntity ToEntity(TDomain domain); } 
  2. 或者你可以尝试找到实体的实例dbcontext使用属性LocalDbSet

     var contextEntity = context.Set<TEntity>().Local .Where(c=>c.Id == entity.Id).FirstOrDefault(); 

您似乎陷入了对抽象中的实现进行编码的过程。 如果将接口注入到泛型而不是具体类型(如EF),则GenericDao会变得更加灵活。 您可以注入任何选择的实现,只要它实现了所需的接口即可。 就您而言,是WCF,文件或其他。 例如;

protected IDbContext _context;

public GenericDao(IDbContext dbContext)
{
    this._context = dbContext;
}

public void Remove(TDomain domain)
{
    _context.Remove(this.ToEntity(domain));
}

//abstraction
public interface IDbContext
{
    void Remove(Entity entity);
}


//EF Implementation
public MyEfClass : IDbContext
{
    public void Remove(Entity entity)
    {
        //code to remove for EF example
        context.Attach(entity);
        context.State = EntityState.Modified;
        context.Set<TEntity>.Remove(entity);
        context.SaveChanges();
    }

}

//WCF Implementation
public MyWCFClass : IDbContext
{
    public void Remove(Entity entity)
    {
        //Wcf implementation here
    }

}

//File example 
public FileWriter : IDbContext
{
    public void Remove(Entity entity)
    {
        LoadFile();
        FindEntry(entity);
        WriteFile(entity);
        SaveFile();
    }
    public void LoadFile()
    {
          //use app settings for file directory
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM