为了简化说明,我以作者和书籍为例。作者 - 书籍具有一对多关系,即一位作者可以写多本书。映射是使用 FluentHibernate 完成的,没有什么特别之处。
我正在尝试查询还没有写任何书的作者。但是当查看在 NHibernate Profiler 中生成的查询时,这不是我所期望的。你们能解决这个错误吗
我期望的结果来自下面的查询
select a.AuthorName
,a.AuthorId from Authors a left outer join Books b on a.AuthorId = b.AuthorId
where b.AuthorId is null
实际生成的查询如下
SELECT AuthorId,
AuthorName,
CreatedAt
FROM Authors
WHERE AuthorId is null
为上述提供的映射
public class AuthorsMap : ClassMap<Author>
{
public AuthorsMap()
{
Table("Authors");
LazyLoad();
Id(x => x.AuthorId).GeneratedBy.Identity().Column("AuthorId");
Map(x => x.AuthorName).Column("AuthorName").Not.Nullable();
Map(x => x.CreatedAt).Column("CreateDatetime").Not.Nullable();
HasMany(x => x.Books).KeyColumn("AuthorId");
}
}
上面是为作者提供的映射,下面是为书籍提供的映射
public class BooksMap : ClassMap<Books>
{
public BooksMap()
{
Table("Books");
LazyLoad();
Id(x => x.BookId).GeneratedBy.Identity().Column("BookId");
References(x => x.Author).Column("AuthorId");
Map(x => x.BookName).Column("BookName").Not.Nullable();
}
}
查询调用如下
Session.Linq<Author>().Where(author => author.Books == null).ToList();
上述的另一种形式导致了对象引用错误
Session.Linq<Author>().Where(author => author.Books.Count == 0).ToList();
性能问题:
来自@Ocelot20 的答案有效,但正在生成 N + 1 个查询以查找记录
Session.Linq<Author>().Where(author => !author.Books.Any()0).ToList();
例子;
作者 1、2、3 没有书,然后在执行 Any() 时运行以下查询
SELECT AuthorId,BookId,BookName from Books Where AuthorId = 1
SELECT AuthorId,BookId,BookName from Books Where AuthorId = 2
SELECT AuthorId,BookId,BookName from Books Where AuthorId = 3
现在这是怎么发生的!!
最佳答案
在这种情况下,我建议使用子查询 而不是JOIN。原因是一旦我们需要切换查询以找出 Authors have some books,JOIN 将乘以结果集(Authors with 2 books 将被列出两次等)
此外,让我们将 NHibernate 本地 Linq 提供程序语法与 Query
一起使用扩展名(需要返回 IQueryable<>
)
实现这一点的语法是:
子选择:
var subquery = session.Query<Book>()
.Select(b => b.Author.AuthorId)
;
没有任何书籍的作者集合
var list = session.Query<Author>()
.Where(a => !subquery.Contains(a.AuthorId))
;
如果我们想要获得拥有一些书籍的作者列表,我们只需删除 NOT 运算符 (!) 并应用分页(Take()
、Skip()
),这将返回正确的结果,而不是相乘的结果。
关于c# - NHibernate to Linq 获取没有出过书的作者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19731894/