zoukankan      html  css  js  c++  java
  • 我所理解的IRepository

        最近有一个项目采用了EntityFramework,对于基本的增删改查操作,我们采用了传统的仓储模式(IRepository),但对于项目中的仓储接口的定义及实现上我认为存在部分缺陷。这个创建模式是以前同事编写好的,然后我们在新项目中利用它。
        
        分页查询接口。
         

        接口定义:

           IEnumerable<T> QueryByPage(Func<T, bool> FunWhere, Func<T, string> FunOrder, int PageSize, int PageIndex, out int recordsCount);
       

      接口实现:

       

            public IEnumerable<T> QueryByPage(Func<T, bool> FunWhere, Func<T, string> FunOrder, int PageSize, int PageIndex, out int recordsCount)
            {
                recordsCount = context.Set<T>().Where(FunWhere).OrderByDescending(FunOrder).Count();
                return context.Set<T>().Where(FunWhere).OrderByDescending(FunOrder).Select(t => t).Skip((PageIndex - 1) * PageSize).Take(PageSize);
            }

        缺陷一:对于仓储接口,集合返回IEnumerable。
        如果返回的是IEnumerable,那么实际上,系统会将表中的所有数据加载到内存中,然后再进行条件过滤,排序,再分页。如果表记录稍微多一点的话,性能可想而知。此种情况下应该推荐返回IQueryable,它才是真正适合和数据库打交道的对象。在客户端应用程序没有访问实际对象值之前,比如ToList()操作,它只是一个编译过程,根据用户传入的参数构建查询计划最终生成用于查询所用的SQLScript脚本。这种方式才是真正意义上的按需所取。
        
        下面我们来定义一个新接口:
       

        IQueryable<T> Query(Expression<Func<T, bool>> filter);

        注意这里是一个开放性特别大的查询接口,如果说不要轻易为客户端开放IQueryable这也没也问题,而且也不推荐将仓储接口直接开放给客户端应用程序,应该在仓储接口上为每个特定的应用系统提供全新的接口,比如可以这样:
       

        public interface Iaspnet_UsersRepository
        {
                 List<aspnet_UsersModel> QueryByPage(Expression<Func<T, bool>> filter, Expression<Func<T, string>> FunOrder, int PageSize, int PageIndex, out int recordsCount);
        }

        这里为了演示方便,就直接调用仓储接口做测试。 
        
        IEnumerable调用代码:
       

    var list = service.QueryByPage(p => p.UserId != Guid.Empty,p=>p.UserName,1,1,out recordsCount).ToList();

        IEnumerable情况下生成的脚本:
       

    SELECT
    [Extent1].[UserId] AS [UserId],
    [Extent1].[UserName] AS [UserName],
    [Extent1].[LoweredUserName] AS [LoweredUserName],
    [Extent1].[MobileAlias] AS [MobileAlias],
    [Extent1].[IsAnonymous] AS [IsAnonymous],
    [Extent1].[LastActivityDate] AS [LastActivityDate]
    FROM [dbo].[aspnet_Users] AS [Extent1]

     
    IQueryable调用

    var list = service.Query(p=>p.UserId!=Guid.Empty).OrderBy(p=>p.UserName).Take(1).Skip(1).ToList();

        IQueryable情况下生成的脚本
     

    View Code
    exec sp_executesql N'SELECT
    [Limit1].[UserId] AS [UserId],
    [Limit1].[UserName] AS [UserName],
    [Limit1].[LoweredUserName] AS [LoweredUserName],
    [Limit1].[MobileAlias] AS [MobileAlias],
    [Limit1].[IsAnonymous] AS [IsAnonymous],
    [Limit1].[LastActivityDate] AS [LastActivityDate]
    FROM ( SELECT [Limit1].[UserId] AS [UserId], [Limit1].[UserName] AS [UserName], [Limit1].[LoweredUserName] AS [LoweredUserName], [Limit1].[MobileAlias] AS [MobileAlias], [Limit1].[IsAnonymous]
    AS [IsAnonymous], [Limit1].[LastActivityDate] AS [LastActivityDate], row_number() OVER (ORDER BY [Limit1].[UserName] ASC) AS [row_number]
        FROM ( SELECT TOP (1) [Project1].[UserId] AS [UserId], [Project1].[UserName] AS [UserName], [Project1].[LoweredUserName] AS [LoweredUserName], [Project1].[MobileAlias] AS
    [MobileAlias], [Project1].[IsAnonymous] AS [IsAnonymous], [Project1].[LastActivityDate] AS [LastActivityDate]
            FROM ( SELECT
                [Extent1].[UserId] AS [UserId],
                [Extent1].[UserName] AS [UserName],
                [Extent1].[LoweredUserName] AS [LoweredUserName],
                [Extent1].[MobileAlias] AS [MobileAlias],
                [Extent1].[IsAnonymous] AS [IsAnonymous],
                [Extent1].[LastActivityDate] AS [LastActivityDate]
                FROM [dbo].[aspnet_Users] AS [Extent1]
                WHERE [Extent1].[UserId] <> @p__linq__0
            )  AS [Project1]
            ORDER BY [Project1].[UserName] ASC
        )  AS [Limit1]
    )  AS [Limit1]
    WHERE [Limit1].[row_number] > 0
    ORDER BY [Limit1].[UserName] ASC
    ',N'@p__linq__0 uniqueidentifier',@p__linq__0='00000000-0000-0000-0000-000000000000'


        小结:

              只有返回IQueryable,才会实现按需所取。尽管这个方法在最上层的服务层没有进行封装,理论上客户端应用程序无法访问到此方法,但既然提供了,而且对外是Public,那么在一定程度上就会对程序员造成误导。
       

     缺陷二:不太实用的接口定义
        我们来看一下这个接口定义
      

    IEnumerable<T> QueryByPage(List<KeyValuePair<stringobject>> queryWhere, List<KeyValuePair<stringint>> funOrder, int PageSize, int PageIndex, out int recordsCount)

        再看下它的实现,可以看出这个方法实现了按需所取,但这是多么的不协调啊(上面那个分页方法就不是按需所取)。就像有人做事一样,50%的工作可以打100分,其余的50%只能打60分,而且这40分很容易得到。
       

    View Code
    string objName = string.Empty;
                Type type = typeof(T);
                var properties = Context.GetType().GetProperties();
                foreach (var propertyInfo in properties)
                {
                    if (propertyInfo.PropertyType.GetGenericArguments()[0].Name == type.Name)
                    {
                        objName = propertyInfo.Name;
                        break;
                    }
                }
                string queryObj = EntitySQLGenerator.GenerateQuery(queryWhere, funOrder, Context.DefaultContainerName, objName);
                IQueryable<T> result = Context.CreateQuery<T>(queryObj);
                recordsCount = result.Count();
                return result.Select(t => t).Skip((PageIndex - 1) * PageSize).Take(PageSize).AsEnumerable<T>();

       查询条件难以理解
       List<KeyValuePair<string, object>>,用户根本不知道需要传递什么参数,提供的接口参数一定要让调用者容易理解。
        
       我理解的仓储接口

       如果还有哪些不够的,可以根据情况再决定增加哪些功能。创建接口不推荐直接开放给客户端,应该在此基础上重新为每个应用定义接口。
      

        public interface IMyRepository<T> where T : classnew()
        {
            T Create();
            T Update(T entity);
            T Insert(T entity);
            void Delete(T entity);
            List<T> FindAll();
            IQueryable<T> Query(Expression<Func<T, bool>> filter);
        }

     

  • 相关阅读:
    Powerful Bash-style command line editing for cmd.exe
    VBA Code for Word Navigation Pane 【failed】 view-showheading-method-word
    network lab simulator
    Global Git ignore
    hosts 持续更新
    TC Hangs when using quick search extended on win10 (1703)
    mybatis缓存机制
    web网上书店总结(jsp+servlet)
    Spring AOP之多切面运行顺序
    C语言实现蛇形矩阵
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/2571503.html
Copyright © 2011-2022 走看看