自定义存储库和工作单元的实现

时间:2012-11-26 22:21:35

标签: c# entity-framework c#-4.0 repository-pattern unit-of-work

在我的ASP.NET MVC 4项目中,我仔细遵循了这个实现Repository和Unit Of Work的例子中的设计原则。

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

我对这篇文章特别感兴趣,该文章是在显示Generic Repository之后编写的:

  

此通用存储库将处理典型的CRUD要求。当特定实体类型具有特殊要求(例如更复杂的过滤或排序)时,您可以创建具有该类型的其他方法的派生类。

由于我的应用符合特定情况,我尝试这样做。我创建了一个GenericRepository,就像文章中的那个,以及一个SharedContext类(SharedContext正是文章中的UnitOfWork类,但这个名字对我来说更有意义)

GenericRepository:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace BusinessLogicLayer.Repositories
{
public class GenericRepository<T> where T: class
{
    internal DbSet<T> _dbSet;
    internal DBConnection _context;

    #region constructors

    public GenericRepository(SharedContext ctx)
    {
        _context = ctx.Context;
    }

    public GenericRepository(DBConnection context)
    {
        _context = context;
        _dbSet = context.Set<T>();
    }
    #endregion

}
}

SharedContext(工作单元)类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BusinessLogicLayer.Repositories
{
public class SharedContext : IDisposable
{
    #region repositories
    private GenericRepository<Entities.Customer> _customerRepository;
    /// <summary>
    /// access the Customer entity
    /// </summary>
    public GenericRepository<Entities.Customer> CustomerRepository
    {
        get 
        {
            if (_customerRepository == null)
                _customerRepository = new GenericRepository<Entities.Customer>(_context);

            return _customerRepository;
        }
    }
    #endregion

    #region context management 

    private Entities.DBConnection _context = new Entities.DBConnection();
    internal Entities.DBConnection Context { get { return _context; } }
    //other methods - save, delete
    #endregion
}
}

现在问题在于:注意我是如何暴露上面的Context属性的 - 我怀疑这实际上是有意的,我觉得我通过这样做打破了模式。我非常喜欢在同一个上下文中通过存储库控制所有内容的想法,但是我需要一些通用存储库不提供的其他方法 - 所以我创建了一个单独的CustomerRepository:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

namespace BusinessLogicLayer.Repositories 
{
public class CustomerRepository: GenericRepository<Entities.Customer>
{
    public CustomerRepository(SharedContext ctx)
        : base(ctx)
    {  }

    public decimal GetCustomerBonusByFrequency()
    {
        //

    }
}
}

...在我的控制器类中,我这样使用:

private SharedContext ctx = new SharedContext();

public PartialViewResult CustomerBonus()
{
   CustomerRepository cRepo = new CustomerRepository(ctx);
   var bonus = cRepo.GetCustomerBonusByFrequency();
   return PartialView(bonus);
}

所以我的两个问题是:

  • 列出项目

    这是添加额外功能的预期方式,文章中提到了吗?我指的是类CustomRepository,这对我来说感觉像是一个模式,因为已经有办法让客户通过GenericRepository(我不再使用)了,而且我暴露了上下文。

  • 如果这很糟糕,那我该怎么做呢?我所需要的只是为我的客户实体提供额外的方法,但是以一种尊重模式的方式。

THX,

编辑:

我需要公开SharedContext中的Context属性,因为如果我删除了GenericRepository中的构造函数(需要一个SharedContext)和CustomerRepository类中的:base(ctx),我得到这个:

  

BusinessLogicLayer.DBModel.Customer不包含带0个参数的构造函数

2 个答案:

答案 0 :(得分:1)

创建专门的客户存储库是正确的做法。我建议您更新SharedContext类,以便CustomerRepository属性返回CustomerRepository类的实例,而不是GenericRepository<Cutomer>

这样,当您从CustomerRepository访问SharedContext属性时,您将拥有通用存储库的方法以及CustomerRepository类的专用方法。< / p>

答案 1 :(得分:1)

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data;

namespace Demo.DAL
{
    public class Repository<TObject>

        where TObject : class
    {
        protected DB Context;
        protected DB Context = null;
        private bool shareContext = false;

        public Repository()
        {
            Context = new DB();
        }

        public Repository(DB context)
        {
            Context = context;
            shareContext = true;
        }

        protected DbSet<TObject> DbSet
        {
            get
            {
                return Context.Set<TObject>();
            }
        }

        public void Dispose()
        {
            if (shareContext && (Context != null))
                Context.Dispose();
        }

        public virtual IQueryable<TObject> All()
        {
            return DbSet.AsQueryable();
        }

        public virtual IQueryable<TObject> 
        Filter(Expression<Func<TObject, bool>> predicate)
        {
            return DbSet.Where(predicate).AsQueryable<TObject>();
        }

        public virtual IQueryable<TObject> Filter(Expression<Func<TObject, bool>> filter,
         out int total, int index = 0, int size = 50)
        {
            int skipCount = index * size;
            var _resetSet = filter != null ? DbSet.Where(filter).AsQueryable() : 
                DbSet.AsQueryable();
            _resetSet = skipCount == 0 ? _resetSet.Take(size) : 
                _resetSet.Skip(skipCount).Take(size);
            total = _resetSet.Count();
            return _resetSet.AsQueryable();
        }

        public bool Contains(Expression<Func<TObject, bool>> predicate)
        {
            return DbSet.Count(predicate) > 0;
        }

        public virtual TObject Find(params object[] keys)
        {
            return DbSet.Find(keys);
        }

        public virtual TObject Find(Expression<Func<TObject, bool>> predicate)
        {
            return DbSet.FirstOrDefault(predicate);
        }

        public virtual TObject Create(TObject TObject)
        {
            var newEntry = DbSet.Add(TObject);
            if (!shareContext)
                Context.SaveChanges();
            return newEntry;
        }

        public virtual int Count
        {
            get
            {
                return DbSet.Count();
            }
        }

        public virtual int Delete(TObject TObject)
        {
            DbSet.Remove(TObject);
            if (!shareContext)
                return Context.SaveChanges();
            return 0;
        }

        public virtual int Update(TObject TObject)
        {
            var entry = Context.Entry(TObject);
            DbSet.Attach(TObject);
            entry.State = EntityState.Modified;
            if (!shareContext)
                return Context.SaveChanges();
            return 0;
        }

        public virtual int Delete(Expression<Func<TObject, bool>> predicate)
        {
            var objects = Filter(predicate);
            foreach (var obj in objects)
                DbSet.Remove(obj);
            if (!shareContext)
                return Context.SaveChanges();
            return 0;
        }
    }
}