ASP MVC 应用程序的存储库模式设计

Posted

技术标签:

【中文标题】ASP MVC 应用程序的存储库模式设计【英文标题】:Repository Pattern Design for a ASP MVC app 【发布时间】:2012-08-26 15:03:15 【问题描述】:

这更多是一个设计问题。

我正在构建一个应用程序,并创建了我的存储库模式结构,如下所示:

我的核心命名空间是 DAL/Repository/BusinessLogic 层程序集。

顺便说一句,我使用 Dapper.NET micro ORM 作为我的数据连接,这就是为什么你会在我的 SqlConnection 对象上看到一个扩展。

为了我的数据访问,我创建了一个基础存储库类:

namespace Core

    public class BaseRepository<T>: IDisposable where T : BaseEntity 
    
        protected SqlConnection conn = null;


        #region Constructors
        public BaseRepository() : this("LOCAL")
        

        

        public BaseRepository(string configurationKey = "LOCAL")
        
            conn = new SqlConnection(ConfigurationManager.ConnectionStrings[configurationKey].ConnectionString);
        
        #endregion

        #region IDisposable
        public void Dispose()
        
            conn.Dispose();
        
        #endregion


        /// <summary>
        /// returns a list of entities
        /// </summary>
        /// <typeparam name="T">BaseEntity type</typeparam>
        /// <param name="sproc">optional parameters, stored procedure name.</param>
        /// <returns>BaseEntity</returns>
        protected virtual IEnumerable<T> GetListEntity(string sproc = null)
        
            string storedProcName = string.Empty;
            if (sproc == null)
            
                storedProcName = "[dbo].sp_GetList_" + typeof(T).ToString().Replace("Core.",string.Empty);
            
            else
            
                storedProcName = sproc;
            

            IEnumerable<T> items = new List<T>();
            try
            
                conn.Open();
                items = conn.Query<T>(storedProcName,
                                                     commandType: CommandType.StoredProcedure);
                conn.Close();
            
            finally
            
                conn.Close();
            


            return items;
        


    

对于我拥有的每个实体,比如说 ExtendedUser, Messages,我正在像这样在 Interface-Class 对上创建它:

namespace Core

    public class ExtendedUserRepository : BaseRepository<UsersExtended>,IExtendedUserRepository
    

        public ExtendedUserRepository() : this("PROD") 
        
        

        public ExtendedUserRepository(string configurationKey) : base(configurationKey)
        
        


        public UsersExtended GetExtendedUser(string username)
        
            var list = GetListEntity().SingleOrDefault(u => u.Username == username);
            return list;
        

        public UsersExtended GetExtendedUser(Guid userid)
        
            throw new NotImplementedException();
        


        public List<UsersExtended> GetListExtendedUser()
        
            throw new NotImplementedException();
        
    

等等

上面的代码只是实体之一:ExtendedUser。

问题是:我应该为我拥有的每个实体创建一个 Interface-ClassThatImplemenetsInterface 对吗?还是应该只有一个 RepositoryClass 和一个 IRepository 接口,其中包含来自我所有实体的所有方法?

【问题讨论】:

我会选择一个通用存储库,你(几乎)已经拥有了:) 【参考方案1】:

具有复杂领域模型的系统通常受益于层,例如 正如 Data Mapper (165) 提供的那样,它隔离了域对象 从数据库访问代码的细节。在这样的系统中,它可以 值得在映射上建立另一层抽象 查询构造代码集中的层。

http://martinfowler.com/eaaCatalog/repository.html

使用通用存储库,您可以使用findBy(array('id' =&gt; 1))findOneBy(array('email' =&gt; 'john@bar.com'))findById()findAll() 等常用方法。确实,它只有一个界面。

您总是需要创建一个具体的实现来指示哪个是由存储库管理的域对象,以完成此getUsersRepository().findAll()

此外,如果您需要更复杂的查询,您可以在具体实现上创建新方法,例如 findMostActiveUsers(),然后在您的应用程序中重用它。

现在,回答您的问题:

您的应用程序至少需要一个接口(通用接口,带有通用方法)。但是,如果您设法拥有特定的方法,就像我上面刚刚提到的那样,您最好拥有另一个接口(例如 RepositoryInterface 和 UsersRepositoryInteface)。

考虑到这一点,您将只依赖存储库接口。查询构造将被具体实现封装。因此,您将能够更改您的存储库实现(例如,使用完整的 ORM)而不影响应用程序的其余部分。

【讨论】:

【参考方案2】:

我认为你不需要无缘无故地创建界面。我什至不明白为什么在这里需要基础存储库类。我什至认为这不是存储库而是 DAL(数据访问层),但这是定义争论。

我认为好的 DAL 实现应该将数据库结构与业务逻辑结构分离——但是硬编码 sp_GetList_XXXEntityNameXXX 模式或在 DAL 之外传递存储过程名称并不是分离的。

如果您认为所有实体列表都是以一种方式获取的,那么您非常乐观或者您的应用程序非常简单,并且您将始终需要业务逻辑中的全套实体而无需任何参数。

仅当您计划替换/包装不同的实现或在一个类中混合几个接口时才需要将接口与实现分离。否则不需要。

在创建存储库时不要考虑实体。存储库包含业务逻辑,应该构建在使用场景之上。拥有像你这样的类更多的是关于数据访问层 - DAL 是建立在你在业务逻辑中需要的查询之上的。可能您永远不会同时需要所有用户的列表 - 但经常需要活动用户、特权用户等的列表。

真的很难预测你需要什么查询——所以我更喜欢从业务逻辑开始设计,顺便添加 DAL 方法。

【讨论】:

“存储库包含业务逻辑,应该建立在使用场景之上” - 你为什么这么说?存储库不应该只是将数据移入和移出吗?业务逻辑不应该有自己的位置/层/类吗? 这取决于名称——我同意你关于分离数据访问和业务逻辑类的观点。我已经将业务逻辑的类命名为“存储库”——这可能会让人感到困惑。有时它称为服务等。 并且接口在存储库类上很有用,以便对控制器或将调用存储库的任何人进行单元测试... 但是我真的同意“很难预测您将需要什么查询 - 所以我更喜欢从业务逻辑开始设计并顺便添加 DAL 方法。” 感谢@STO 的回复。点了,我明白你在这里的意思。整个“存储库”接口的想法是更好地支持单元测试,但我应该从业务逻辑层开始

以上是关于ASP MVC 应用程序的存储库模式设计的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 的最佳存储库模式

ASP.NET MVC:BLL 和 DAL 到存储库设计

如何在 ASP MVC 中实现工作单元、存储库和业务逻辑?

在使用 IdentityDbContext 的情况下,如何在 ASP.NET Core MVC 中使用存储库模式?

在使用 ASP.NET MVC 和 ORM 解决方案时,我们是不是需要使用存储库模式?

实现存储库模式的最佳方法?