【问题标题】:Generic UnitOfWork and Repository通用工作单元和存储库
【发布时间】:2014-11-19 07:30:00
【问题描述】:

我正在重构我的代码,我首先在我的服务层中删除了对实体框架的引用。该层使用位于我的 DAL 层中的工作单元和存储库(通过接口)。

现在我遇到了一个问题,因为我的基础存储库类如下所示:

public interface IDatabaseFactory<C> : IDisposable
{
    C Get();
    void Set(string connectionString);
}

public abstract class Repository<C, T> : IRepository<T> 
                                         where C : DbContext, IBaseContext 
                                         where T : class, IEntity
{
    protected readonly IDbSet<T> dbset;
    private C dataContext;

    protected Repository(IDatabaseFactory<C> databaseFactory)
    {
        this.DatabaseFactory = databaseFactory;
        this.dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory<C> DatabaseFactory
    {
        get;
        private set;
    }

    protected C DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    public virtual void Add(T entity)
    {
        dbset.Add(entity);
    }

    //etc...
}

我显然需要 C 类型的 DbContext 约束。但是,如果这样做,我会在 dataContext 上收到错误,因为它无法解析 DbContext 中的 C。

我该如何克服这个问题?

编辑

典型的存储库如下所示:

public interface ICustomerTypeRepository : IRepository<CustomerType> { }

public class CustomerTypeRepository : Repository<IBaseContext, CustomerType>, ICustomerTypeRepository
{
    public CustomerTypeRepository(IDatabaseFactory<IBaseContext> databaseFactory)
        : base(databaseFactory) { }
}

在下面建议的更改之后,我仍然得到相同的错误:

类型“IBaseContext”不能用作泛型类型或方法“Repository”中的类型参数“TContext”。没有从“IBaseContext”到“System.Data.Entity.DbContext”的隐式引用转换。

【问题讨论】:

  • IDatabaseFactory&lt;C&gt; 是如何定义的?
  • 您使用DataContext 仅用于获取DbSet
  • @Vlad 是的。我正在考虑完全删除 IDatabaseFactory。也许我可以在构造函数中传递 IUnitOfWork 。上下文在 UnitOfWork 类中。

标签: c# entity-framework asp.net-web-api


【解决方案1】:

要修复编译错误,您必须对泛型类型施加适当的约束(为了便于阅读,我已将 C 替换为 TContext):

interface IBaseContext { }
interface IDatabaseFactory<TContext> : IDisposable
    where TContext : DbContext
{
    TContext Get();
    void Set(string connectionString);
}

interface IEntity { }
interface IRepository<T> 
    where T : class, IEntity
{ }

abstract class Repository<TContext, T> : IRepository<T>
    where TContext : DbContext, IBaseContext
    where T : class, IEntity
{
    protected readonly IDbSet<T> dbset;
    private TContext dataContext;

    protected Repository(IDatabaseFactory<TContext> databaseFactory)
    {
        this.DatabaseFactory = databaseFactory;
        this.dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory<TContext> DatabaseFactory { get; private set; }
    protected TContext DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    public virtual void Add(T entity)
    {
        dbset.Add(entity);
    }

    //etc...
}

但从架构的角度来看,在存储库中持有对DbContext 的引用似乎是多余的。当然,如果不了解您的所有类型,就很难提出更好的解决方案。

【讨论】:

    【解决方案2】:

    要从代码中删除 DbContext,您需要像这样更改 IDatabaseFactory:

    public interface IDatabaseFactory : IDisposable
    {
        T Set<T>() where T : IEntity;
    }
    

    然后你可以更改存储库

    public abstract class Repository<T> : IRepository<T> 
                                         where T : class, IEntity
    {
        protected readonly IDbSet<T> dbset;
    
        protected Repository(IDatabaseFactory databaseFactory)
        {
            this.dbset = databaseFactory.Set<T>();
        }
        // other code
    }
    

    IDatabaseFactory的实现:

    public class DatabaseFactory : IDatabaseFactory
    {
        private readonly DbContext _context;
    
        public DatabaseFactory(DbContext context)
        {
            _context = context;
        }
    
        public T Set<T>() where T : Entity
        {
            return _context.Set<T>();
        }
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-27
      • 2015-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多