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

时间:2012-08-31 19:19:49

标签: asp.net-mvc design-patterns architecture repository-pattern data-access-layer

这更像是一个设计问题。

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

我的核心名称空间是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接口以及我所有实体的所有方法?

2 个答案:

答案 0 :(得分:1)

我认为你不需要在没有原因的情况下创建界面。我甚至不明白你为什么需要基础知识库类。我甚至认为这不是存储库,而是DAL(数据访问层),但这是一个明确的争论。

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

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

只有在计划替换/包装不同的实现或在一个类中混合少量接口时,才需要将接口与实现分开。否则不需要。

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

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

答案 1 :(得分:1)

  

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

     

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

使用通用存储库,您可以使用常见方法,例如findBy(array('id' => 1))findOneBy(array('email' => 'john@bar.com'))findById()findAll()等。实际上,它将有一个界面。

您将始终必须创建一个具体实现,该实现将指示哪个是将由存储库管理的域对象,以实现此目的getUsersRepository().findAll()

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

现在,回答你的问题:

您的应用程序将至少期望一个接口(通用方法)。但是如果你设法有特定的方法,比如我上面提到的方法,你最好有另一个接口(例如RepositoryInterface和UsersRepositoryInteface)。

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