C# 通用存储和UnitOfWork定制

C# 通用存储和UnitOfWork定制,c#,entity-framework-5,repository-pattern,unit-of-work,C#,Entity Framework 5,Repository Pattern,Unit Of Work,我正在从头开始从事ASP.NETMVC4项目。我决定使用entityframework5和code-First工作流从数据访问层开始。我曾经工作过的公司(在我看来)使用了非常好的存储库模式的实现,包括存储库、服务、存储库和服务的抽象工厂,以及DI的Unity。我试着重做,但它对我来说太复杂了,要复制我在那里使用的东西会花费我很多时间,所以我决定做一些研究,买一些更轻的 因此,我决定使用GenericRepository和UnitOfWork——与最初的计划相去甚远,但这是我大部分搜索中显示的实现

我正在从头开始从事ASP.NETMVC4项目。我决定使用
entityframework5
code-First
工作流从数据访问层开始。我曾经工作过的公司(在我看来)使用了非常好的
存储库模式的实现,包括存储库、服务、存储库和服务的抽象工厂,以及
DI
Unity
。我试着重做,但它对我来说太复杂了,要复制我在那里使用的东西会花费我很多时间,所以我决定做一些研究,买一些更轻的

因此,我决定使用
GenericRepository
UnitOfWork
——与最初的计划相去甚远,但这是我大部分搜索中显示的实现。所以我做了一个非常基本的实现(我确信我知道发生了什么,甚至可能低于我的理解能力),实际上我认为对于这个确切的项目来说,这可能就足够了,但我想要的是能够在不同的实体上调用额外的自定义方法

我认为这从泛型存储库的思想中得到了很多东西,但是如果我尝试使用其他实现,它会变得越来越困难,所以我想知道是否有一种方法可以将它添加到我的实现中,而不会对泛型存储库背后的思想造成太大的伤害

我现在拥有的是
GenericRepository
类:

public class GenericRepository<TEntity> where TEntity : class
    {
        internal DBContext context;
        internal DbSet<TEntity> dbSet;

        public GenericRepository(DBContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get()
        {
            IQueryable<TEntity> query = dbSet;
            return query.ToList();
        }
        //just the standard implementation
public class UnitOfWork : IDisposable
    {
        private DBContext context = new DBContext();
        private CustomerRepository customerRepository;

        public CustomerRepository CustomerRepository
        {
            get
            {
                if (this.customerRepository == null)
                    this.customerRepository = new CustomerRepository(context);
                return customerRepository;
            }
        }

        private GenericRepository<Order> orderRepository;

        public GenericRepository<Order> orderRepository
        {
            get
            {
因此,正如您可能看到的那样,我的
订单
实体正在使用
一般存储
但我制作了一个测试类
客户存储
用于我的
客户
实体

目前,此类
CustomerRepository
如下所示:

public class CustomerRepository : GenericRepository<Customer>
    {
        public CustomerRepository(DBContext context) : base(context) { }
    }
公共类CustomerRepository:GenericRepository
{
公共CustomerRepository(DBContext上下文):基(上下文){}
}

我们的想法是在这里添加显式用于
Customer
实体的方法。我不确定这是否正确,尤其是我调用构造函数的方式。但是,为不同实体添加这些特定方法的自然方式是什么?我甚至不介意退一步来更好地实现它,但我不想仓促行事,因为我已经尝试过了,目前整个概念对我来说太复杂了,我想确保我理解我在代码中使用的东西。

我认为你的思路是正确的。以下是我使用的通用存储库:

public interface IRepository<TEntity>
    where TEntity : class
{
    IQueryable<TEntity> GetAll();
    IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate);
    TEntity GetById(long id);
    void Add(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

public class Repository<TEntity> : IRepository<TEntity>
    where TEntity : class
{
    protected readonly DbEntities Context;
    protected readonly DbSet<TEntity> Set;

    public Repository()
    {
        Context = new DbEntities();
        Set = Context.Set<TEntity>();
    }

    public virtual IQueryable<TEntity> GetAll()
    {
        return Set;
    }

    public virtual IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
    {
        return Set.Where(predicate);
    }

    public virtual TEntity GetById(long id)
    {
        return Set.Find(id);
    }

    public virtual void Add(TEntity entity)
    {
        Set.Add(entity);
        Context.SaveChanges();
    }

    public virtual void Update(TEntity entity)
    {
        Set.Attach(entity);
        Context.Entry(entity).State = EntityState.Modified;
        Context.SaveChanges();
    }

    public virtual void Delete(TEntity entity)
    {
        Set.Remove(entity);
        Context.SaveChanges();
    }
}


// And assuming User is a data object with an Id property:
public interface IUserSpecificRepository
{
    List<User> GetById(long id)
}

public class UserSpecificRepository : IUserSpecificRepository, Repository<User>
{
    public virtual List<User> GetById(long id)
    {
        return GetBy(x => x.Id = id).ToList();
    }
}
公共接口IRepository
地点:班级
{
IQueryable GetAll();
IQueryable GetBy(表达式谓词);
TEntity GetById(长id);
无效添加(潜在实体);
无效更新(潜在实体);
无效删除(潜在实体);
}
公共类存储库:IRepository
地点:班级
{
受保护的只读DbEntities上下文;
受保护的只读数据库集;
公共存储库()
{
Context=新的DbEntities();
Set=Context.Set();
}
公共虚拟IQueryable GetAll()
{
返回集;
}
公共虚拟IQueryable GetBy(表达式谓词)
{
返回集。其中(谓词);
}
公共虚拟实体GetById(长id)
{
返回Set.Find(id);
}
公共虚拟空添加(TEntity实体)
{
设置、添加(实体);
SaveChanges();
}
公共虚拟无效更新(TEntity实体)
{
集合。附加(实体);
Context.Entry(entity.State=EntityState.Modified;
SaveChanges();
}
公共虚拟无效删除(TEntity实体)
{
设置、删除(实体);
SaveChanges();
}
}
//假设用户是具有Id属性的数据对象:
公共接口IUserSpecificRepository
{
列表GetById(长id)
}
公共类UserSpecificRepository:IUserSpecificRepository,Repository
{
公共虚拟列表GetById(长id)
{
返回GetBy(x=>x.Id=Id.ToList();
}
}
请注意,
GetAll()
GetBy()
返回一个queryable。这是为了允许控制查询表达式何时转换为SQL并访问数据库。通常,调用
ToList()
会导致这种情况。然后可以从中继承,任何自定义方法都可以使用这两个启动程序方法

另外,根据一般经验,您永远不应该像现在这样执行
GetAll().ToList()
。如果你有大量的记录,你会遇到问题。如果要筛选到几个记录,这也是一个性能问题
GetAll().ToList()。其中(x=>x.Id=1)
基本上是将数据库中的大量记录都存储到内存中,然后将其过滤为一条。您应该改为执行此操作
GetAll().Where(x=>x.Id=1).ToList()


希望这对你有帮助

请注意,DbEntities是EF DBContext。因此,当您想添加用于某些实体的其他方法时,您在做什么?创建接口,例如-
IUserRepository:IRepository
,然后创建类-
UserRepository:Repository,IUserRepository
?您可以添加一个示例,说明如何在此上下文中扩展此体系结构吗?我在示例中添加了一个
userspecificsrepository
。它只有一个方法,但它应该为您想要创建的任何类型化存储库提供一个框架。如果您希望通过
iuserspecificreepository
公开泛型方法,那么只需将其从
IRepository
继承即可。您应该查看