【转】Repository 再次来到 IQueryable?仍然 IEnumerable?

好处:

当 BookApplication 操作变的简约的时候,BookRepository 也会相应变的简短:

 

  1. 延迟执行。
  2. 削减 Repository 重复代码(GetBy…)。
  3. IQueryable 提供更好的灵活性。

原文:http://www.cnblogs.com/xishuai/p/repository-return-iqueryable-or-ienumerable.html

那是一个很有意思的题材,大家一步一步来研究,首先必要肯定五个概念(来自
MSDN):

地点是大家的形似接口设计,包括查询、伸张、删除操作,你发觉并不曾改动,其实大家得以先经过
GetById 操作,然后拿走 Book 对象,进行改动,最终执行 SaveChanges
就可以了,在持久化数据库的时候,会判定实体状态值的概念,最后举行应用改变。

下边大家先达成 Repository 重临 IEnumerable:

using EntityFramework.Extensions;

public class BookApplication : IBookApplication  
{
    private IBookRepository _bookRepository;

    public BookApplication(IBookRepository bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public void UpdateNameById(int bookId, string bookName)
    {
        IQueryable<Book> books = _bookRepository.GetBooks();
        books = books.Where(b => b.bookId == bookId);
        books.Update<Book>(b => new Book { BookName = bookName });
    }

    public void UpdateNameByIds(int[] bookIds, string bookName)
    {
        IQueryable<Book> books = _bookRepository.GetBooks();
        books = books.Where(b => bookIds.Contains(bookIds));
        books.Update<Book>(b => new Book { BookName = bookName });
    }

    public void Delete(int id)
    {
        IQueryable<Book> books = _bookRepository.GetBooks();
        books = books.Where(b => b.bookId == id);
        books.Delete<Book>();
    }
}

 

关于 Repository Pattern and
IQueryable
 那篇博文,我想再说一下,因为这些老外的见地相当赞,首先,它是根据Repository 情势概念基础上说的,所以,大家一先导说:在“伪
DDD”设计中,你可以把 Repository
看作是多少访问层。那是四个例外的前提,我再大概总括下那些老外的见识:

  1. 隔断单元测试。
  2. 数量访问在 Repository 之外落成。
  3. 数据访问极度在 Repository 之外抛出。
  4. 该领域层将充满着那个卓殊详细询问。

因为 IQueryable 是延迟查询,唯有在推行 AsEnumerable
的时候,才会真正去查询,也足以那样说,BookApplication
可以根据需求任意构建查询表明式树,如同大家在 SQL Server 中写查询
SQL,SELECT * FORM Books 在 BookRepository
中实行构建,WHERE ... 操作在 BookApplication 中举办构建,最终的 F5
执行也在 BookApplication 中。

 


public interface IBookRepository  
{
    Book GetById();
    IEnumerable<Book> GetAllBooks();
    IEnumerable<Book> GetBy....();
    void Add(Book book);
    void Delete(Book book);
    void SaveChanges();
}

 

便宜就不多说了,因为我们地方已经施行过了,关于坏处,“隔离单元测试”是如何看头啊?也就是说我们无法很好的对
Repository 举办单元测试,一方面是因为 IRepository
是那么的粗略(就八个章程),另一方面 IQueryable
是查询表明树,它并不是到位时,唯有在切切实实调用的时候才会询问已毕,所以,对于
Repository 的单元测试,分明是没有其余意义的。

至于 EntityFramework.Extended
的增加,需求记录下,因为那一个事物确实格外好,改变了大家事先的很多写法和题材,比如,在前边运用
EF 进行改动和删除实体,大家一般会这一个写:

地方只是一些,关于那类的小说,老外写的老大多,而且评论中的钻探也万分热烈,因为斯拉维尼亚语实在差,我大约看了有些,出乎我预想之外的是,很两人都不支持Repository 再次回到IQueryable,但座谈的却相当有趣,比如有个老外那样咋舌:I’m still not
convinced that returning IQueryable is a bad idea, but at least I’m far
more aware of the arguments against it. 差不离意思是:我如故不信任返回IQueryable
是一个坏主意,但最少我更驾驭她们的反对理由,是否很风趣啊?

故而呢,假若您的序列是“伪 DDD”,并且 Repository
是被你作为“数据访问层”,那么使用 IQueryable 就没啥问题了。

 

GetBy….() 代表了一类查询办法,因为大家的工作比较复杂,对 Book
的查询会千奇百怪,所以,没有章程,大家只能扩展种种查询艺术来满足急需,最终可能导致的结果是,一个
Where 对应一个查询艺术,IBookRepository
会充斥着各样查询形式,并且这么些查询办法一般只会被一个 Application
方法调用,如果你查看下 GetBy….()
方法完成,会发觉其实都大致,差其余只是 Where
条件,那样的结果就会招致代码变得相当的重叠。

public interface IBookRepository  
{
    IQueryable<Book> GetBooks();
    void SaveChanges();//只用于Books.Add(book);
}

从地点的代码中,大家可以见到,IQueryable 很好的解决了利用 IEnumerable
所出现的题目,一个查询可以应对云谲波诡的运用查询,IQueryable
看起来好像是那么的强有力,其实 IQueryable
的兵不血刃并不限于此,下面说的是询问表明式,那添加、修改和删除操作,可以接纳它举办完毕吗?修改和删除是可以的,添加并不可以,具体可以参照
dudu
的那篇博文:付出笔记:基于EntityFramework.Extended用EF完成指定字段的换代

  

有没有觉察怎么两样呢?原来 IQueryable
还是能这么写?那货居然不只是用来查询,也足以用来删除和修改,此外,通过追踪生成的
SQL 代码,你会意识,没有了 SELECT,和大家直接写 SQL
是千篇一律的功效,在实施修改和删除此前,大家须要对查询表达树举行过滤,也就是说的,当大家最终接纳修改的时候,会是在那些过滤的询问表明树基础上的,比如上边的
Delete 操作,大家先经过 bookId 举行过滤,然后直接进行 Delete
就能够了,哇塞,原来是那般的简要。

本着地点的题目,如何是好呢?因为 IEnumerable
是查询在本土内存中,所以并未艺术,我们只好这么处理,这什么使用
IQueryable 会是什么样的吧?大家看下代码:

一个 IQueryable 表明树,一个 SaveChanges 操作,就能够满足BookApplication 中的所有操作。

  • However the mistake is not the IQueryable itself, but its
    purpose.(不是 IQueryable 本身的错误,而是它的目标。)
  • The point is that using IQueryable, you’re asking for a query
    builder and not for a model.(问题的要紧是,使用 IQueryable
    是一个查询生成器,而不是一个模子。)
  • we want to specify what to get, not how to get
    it.(大家想通过轨道获得它,而不是何许去获得。)
  • tell it the what, not the how.
public class BookApplication : IBookApplication  
{
    private IBookRepository _bookRepository;

    public BookApplication(IBookRepository bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public IEnumerable<Book> GetAllBooks()
    {
        return _bookRepository.GetBooks().AsEnumerable();
    }

    public IEnumerable<Book> GetBooksByUser(int userId)
    {
        return _bookRepository.GetBooks().Where(b => b.UserId == userId).AsEnumerable();
    }

    //....
}

只有一个 GetBooks 查询,那它能满意各个查询须要吗?我们看下 Application
中调用的代码:

public class BookApplication : IBookApplication  
{
    private IBookRepository _bookRepository;

    public BookApplication(IBookRepository bookRepository)
    {
        _bookRepository = bookRepository;
    }

    public void UpdateNameById(int bookId, string bookName)
    {
        var book = _bookRepository.GetById(bookId);
        book.BookName = bookName;
        _bookRepository.SaveChanges();
    }

    public void UpdateNameByIds(int[] bookIds, string bookName)
    {
        var books = _bookRepository.GetBooksByIds(bookIds);
        foreach (var book in books)
        {
            book.BookName = bookName;
        }
        _bookRepository.SaveChanges();
    }

    public void Delete(int id)
    {
        var book = _bookRepository.GetById(id);
        _bookRepository.Delete(book);//context.Books.Remove(book);
        _bookRepository.SaveChanges();
    }
}
  • IQueryable:提供对未指定数据类型的一定数据源的询问进行计算的出力。
  • IEnumerable:公开枚举数,该枚举数援助在非泛型集合上拓展简短迭代。
public interface IBookRepository  
{
    IQueryable<Book> GetBooks();
    void Add(Book book);
    void Delete(Book book);
    void SaveChanges();
}

IQueryable 继承自 IEnumerable,它们俩最大的分别是,IQueryable
是表明式树处理,可以顺延查询,而 IEnumerable
只好查询在本土内存中,Repository 的概念就不多说了,在“伪
DDD”设计中,你可以把它当作是数码访问层。

 

看了地点,是还是不是多少茅塞顿开的感觉到呢,其实从 Repository
的形式概念方面考虑,使用 IQueryable
确实不是很适合,但不可不可以认的是,IQueryable
又那样强大和有益,如何是好吧?就如博文一先河强调的那么:Repository
的定义就不多说了,在“伪 DDD”设计中,你可以把它作为是数据访问层。

上边的写法有哪些问题吗?其实最大的题材就是,我们要拓展修改和删除,必须先拿走那些实体,也就是先查询再进行修改和删除,这几个就不怎么多余了,越发是
UpdateNameByIds 中的批量改动,先拿走 Book
对象列表,然后再遍历修改,最终保存,是还是不是有点 XXX
的痛感呢,仔细记挂,还不如不用 EF 来的粗略,因为一个 Update SQL
就可以搞定,简单并且性能又高,为啥还要接纳 EF 呢?那是一个坑?其实选取EF 也可以实施 SQL,但那就像是换了个马甲,没有何样卵用。

既然 IQueryable 是那样的精锐,那用它就好了,为啥还要研究吗?如果您
Google 搜索“Repository
IQueryable”关键词,会发觉多量的相干小说,我先贴出几个相当赞的探讨:

有关 Repository 再次来到 IQueryable 的座谈,我大致总括下:

 

本着地点的题材,该怎么化解呢?很简短,使用 EntityFramework.Extended 和
IQueryable 就可以,我们改造下方面的代码:

坏处:

相关文章