我所理解的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情况下生成的脚本
 

ExpandedBlockStart.gif 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分很容易得到。
   

ExpandedBlockStart.gif 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);
    }

 

转载于:https://www.cnblogs.com/ASPNET2008/archive/2012/06/30/2571503.html

《代码库》1.0 主要功能简介 《代码库》是专为程序员设计的一个源码管理工具。她可以使编程变得更为有趣,降低您的重复劳动;她虽然不能立即提高您的编程技能,但能够让您在开发软件的过程中节省时间与金钱。在现代软件开发过程中,个人英雄式的完成一个从最底层开发的软件是极为困难的,因为您得为您的程序准备一切,但您愿意重写您以前写过的所有子程序吗。而实际上在开发的同时,可以将一些好的代码片断、算法加以摘录,并保存在《代码库》中,可以随时查阅、编辑您所收集的知识,并将能利用的代码加入您的程序中,提高开发速度。 《代码库》是一个基于文本格式的工具,采用树型目录进行的知识分类管理,您可以在她的帮助下清晰、准确的管理您收集的优秀代码。《代码库》使用自身的库数据结构, 并支持库形式的导出、导入,也支持文本文件的导出、导入,支持Windows粘贴板复制(支持TXT、RTF格式)、粘贴,功能丰富的编辑:支持Undo操作、显示行号、调整tab字符数、增加/减少缩进、设置当次缩进的字符数、换行显示,支持语法高亮显示、编辑修改(目前版本支持九种语法标识:Plain Text, Object Pascal, ANSI C, Java, Visual Basic, eMail, IniFile, Html/JS/VBS , PL/SQL),支持功能强大的全库查找和搜索功能,提供打印及打印预览功能。《代码库》是专门为程序员进行设计的,因此我们知道什么是您最需要的,也会最好的东西带给您。 感谢David Brock的控件(TSyntaxMemo v3.00.36)以及Jordan Russell的控件(Toolbar2000 v3.0)。另感谢Wzy兄帮忙进行测试! 另外您可以随意复制、散发本软件,但是不得对本软件作任何修改。作者保留《代码库》的版权。本人将不定期的更新本软件,最新版的《代码库》请到www.csdn.net的共享软件栏目中寻找。 建议运行环境Windows98、Win2000、WinXP,内存64M以上。 如果您在使用中发现有什么bug或有什么建议,请及时通知我iRepository@citiz.net,本人将尽快回复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值