2010-05-05 43 views
14

我有一个具有属性集合的根对象。作为根属性的NHibernate IQueryable集合

例如:

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;} 
} 

我想做到的是返回一个集合,是IQueryable的,这样我可以从父直接运行寻呼和过滤掉的集合。

var shelf = shelfRepository.Get(1); 

var filtered = from book in shelf.Books 
       where book.Name == "The Great Gatsby" 
       select book; 

我想有由NHibernate的具体执行的查询,并没有得到所有加载整个集合,然后在内存中分析它(这是当我使用的ICollection什么目前发生)。

这背后的原因是,我的收藏可能是巨大的,成千上万的记录,并且让所有的查询可以来砸我的数据库。

我想,这样当NHibernate的看在我的班级一个IQueryable它知道怎样做才能做到这一点含蓄。

我已经看过了NHibernate的LINQ提供程序,目前我正在服用大集合和他们分裂成自己的资源库,这样我可以作出的筛选和分页显式调用的决定。

的LINQ to SQL提供类似于我在谈论的东西。

回答

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>(); 

有有一个问题,但是:

  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); 
} 

如果有人可能会消耗是这样的:

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

呸!你正在通过你的领域模型消除你的持久性需求!也许你可以把它由具有存储库少一些糟糕发出的IQueryable,它在运行时实际上是LINQ NHibernate的:

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

还是蛮等等。

创建您自己的自定义集合类型(可能是IQueryable实现),它包装实际书籍的专用字段,并将NHibernate映射到该字段。但是,使用ISession.CreateFilter可能会遇到困难。您必须考虑“发现”当前会话,将LINQ表达式转换为您可以在CreateFilter中使用的东西等。另外,您的业务逻辑仍然依赖于NHibernate。

在这一点上没有什么可以满足的。直到NHibernate可以为您的集合执行LINQ之前,看起来您最好像查询过的那样正常查询您的Book存储库,即使它看起来不够性感或最佳。

+0

谢谢你的解释如此详尽。我想过你说过的话,我同意你提出的所有观点。不知道NHibernate 3是否会支持这个开箱即用的功能。 – 2010-05-15 14:19:42

1

也许你应该试一试Nhibernate Linq。它允许您使用IQueryable的和不喜欢的事情:

Session.Linq<Book>().Where(b => b.Name == "The Great Gatsby"); 
+0

“我看过NHibernates Linq提供程序,目前我正在决定采用大型集合并将它们拆分到自己的存储库中,以便我可以明确调用筛选和分页。” – 2010-05-06 01:16:00

+2

@哈立德 - 我不知道为什么这不会帮助你。这正是你要求的 – Dann 2010-05-06 08:14:37

+0

我的问题是“我如何获得NHibernate映射到IQueryable属性?”我已经知道NHibernate Linq。这是我从未问过的问题的答案,这就是为什么我投了票。 – 2010-05-07 13:31:10

3

我倾向于认为是这样的:

总根源是一致的边界,因此,如果货架需要实施某种书本上的一致性政策它包含,那么它应该是一个聚合根。 而在这种情况下,它应该拥有一套/一套书。

如果你不需要从架子上的书执行任何方式的一致性,那么我会考虑删除组/集合属性,然后将这些查询到存储库来代替。

而且,由于分页和筛选最有可能没有什么与你的域逻辑,它是最有可能的表现。 然后我会考虑为它制作一些特别的视图,而不是向我的存储库添加演示设备。

例如

var result = Queries.FindBooksByShelf(shelfId,pageSize); 

这种查询可以返回的突起和/或作为普通的SQL优化等 他们是有一定看法最有可能的特定或在您的GUI报告。 这样你的域名将只专注于域名概念。

相关问题