1

在我的 ASP.NET MVC 4 项目中,我仔细遵循了实现存储库和工作单元的示例中的设计原则。

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-应用程序

我对文章中的这句话特别感兴趣,是在展示了通用存储库之后写的:

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

由于我的应用程序符合这种特殊情况,因此我尝试这样做。我做了一个 GenericRepository 就像文章中的一样,还有一个 SharedContext 类(SharedContext 正是文章中的 UnitOfWork 类,但这个名字对我来说更有意义)

通用存储库:

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(我不再使用)获取客户,而且我正在公开上下文。

  • 如果这很糟糕,那么我应该如何正确地做到这一点?我只需要为我的客户实体提供额外的方法,但要以尊重模式的方式。

谢谢,

编辑:

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

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

4

2 回答 2

1

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

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

于 2012-11-26T23:22:59.157 回答
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;
        }
    }
} 
于 2013-01-10T11:23:41.833 回答