NHibernate IQueryable集合作为root的属性

Kha*_*meh 14 c# nhibernate domain-driven-design fluent-nhibernate

我有一个根对象,其属性是一个集合.

例如:

I have a Shelf object that has Books.

// Now
public class Shelf 
{
    public ICollection<Book> Books {get; set;}
}

// Want 
public class Shelf 
{
   public IQueryable<Book> Books {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

我想要完成的是返回一个IQueryable的集合,这样我就可以直接从父节点运行分页和过滤集合.

var shelf = shelfRepository.Get(1);

var filtered = from book in shelf.Books
               where book.Name == "The Great Gatsby"
               select book;
Run Code Online (Sandbox Code Playgroud)

我希望NHibernate专门执行该查询,而不是全部加载整个集合,然后在内存中解析它(这是我使用ICollection时当前发生的事情).

这背后的原因是我的收藏可能是巨大的,成千上万的记录,并且获取所有查询可能会破坏我的数据库.

我想隐含地这样做,以便当NHibernate在我的课上看到IQueryable时它知道该怎么做.

我查看了NHibernate的LINQ提供程序,目前我正在决定采用大型集合并将它们拆分到自己的存储库中,以便我可以显式调用过滤和分页.

LINQ To SQL提供类似于我所说的内容.

Hac*_*ese 12

我一直在努力想出一个类似问题的解决方案.

您可以使用来过滤实体的集合ISession.FilterCollection.这会创建一个额外的IQuery,您可以在其中计算,页面,添加条件等.

所以,例如(我在FilterCollection中的查询可能有点偏,但你应该明白):

ISession session = GetSession();
var shelf = session.Get<Shelf>(id);
var books = session.FilterCollection(shelf.Books, "where Name = :title").SetString("title", "The Great Gatsby").List<Book>();
Run Code Online (Sandbox Code Playgroud)

但是有一个问题:

  1. 执行代码的使用者需要访问ISession.CreateFilter,或者您需要在存储库中创建一个方法,该方法接收属性,查询和查询参数(以及任何分页或其他信息).这不是地球上最性感的东西.
  2. 这不是你想要的LINQ.

不幸的是,我认为没有任何方法可以通过NHibernate获得你想要的东西.你可以假装它,如果你想尝试,但它们似乎对我不利:

添加一个方法或属性,它为这个架子返回一个LINQ to NHibernate IQueryable:

public IQueryable<Book> FindBooks() {
  return Resolver.Get<ISession>().Linq<Book>().Where(b => b.Shelf == this);
}
Run Code Online (Sandbox Code Playgroud)

有人可能会像这样消费:

var shelf = ShelfRepo.Get(id);
var books = (from book shelf.FindBooks()
             where book.Title == "The Great Gatsby"
             select book);
Run Code Online (Sandbox Code Playgroud)

呸!您正在通过域模型消除持久性需求!也许你可以通过让一个存储库发出IQueryable来使它变得更糟糕,它在运行时实际上是LINQ to NHibernate:

public IQueryable<Book> FindBooks() {
  return Resolver.Get<IRepository<Book>>().CreateQuery().Where(b => b.Shelf == this);
}
Run Code Online (Sandbox Code Playgroud)

还是很糟糕.

创建自己的自定义集合类型(可能是IQueryable实现),它包装实际书籍的私有字段,并将NHibernate映射到该字段.但是,使用ISession.CreateFilter进行工作可能很困难.您必须考虑"发现"当前会话,将LINQ表达式转换为您可以在CreateFilter中使用的内容等.此外,您的业务逻辑仍然依赖于NHibernate.

在这一点上,没有什么能真正满足.直到NHibernate可以为你的集合做LINQ,看起来你最好只是像已经建议的那样正常查询你的Book存储库,即使它看起来不那么性感或最佳.