我有一个根对象,其属性是一个集合。
例如:
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提供类似于我所说的内容。
答案 0 :(得分: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>();
但是有一个问题:
不幸的是,我认为没有任何办法可以通过NHibernate获得你想要的东西。如果你想尝试的话,你可以假装它,但它们似乎对我不利:
添加一个方法或属性,该方法或属性为此架子返回LINQ到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存储库,即使它看起来不那么性感或最佳。
答案 1 :(得分:3)
我倾向于这样想:
聚合根是一致性的边界,因此如果架构需要在其包含的书籍上强制执行某种一致性策略,那么它应该是聚合根。 在这种情况下,它应该有一套/一套书。
如果您不需要以任何方式强化从书架到书籍的一致性,那么我会考虑删除set / collection属性并将这些查询移到存储库中。
此外,由于分页和过滤很可能与您的域逻辑没有任何关系,因此最有可能进行演示。 然后我会考虑为它制作一些特殊的视图,而不是向我的存储库添加演示设备。
e.g。
var result = Queries.FindBooksByShelf(shelfId,pageSize);
此类查询可以返回投影和/或优化为纯SQL等。 它们很可能特定于GUI中的某个视图或报表。 这样,您的域名将仅关注域概念。
答案 2 :(得分:1)
也许你应该试试Nhibernate Linq。它允许您使用IQueryable并执行以下操作:
Session.Linq<Book>().Where(b => b.Name == "The Great Gatsby");