C# NHibernate给Linq找没有写过书的作者
我以作者和书籍为例,使解释变得简单。作者-书有一对多的关系,即一个作者可以写许多书。映射是使用FluentHibernate完成的,它们没有任何特殊之处 我试图询问那些还没有写过书的作者。但是当查看在NHibernate Profiler中生成的查询时,它并不是我所期望的。你们能把这个错误处理掉吗 我期望的结果来自下面的查询C# NHibernate给Linq找没有写过书的作者,c#,sql,linq,nhibernate,C#,Sql,Linq,Nhibernate,我以作者和书籍为例,使解释变得简单。作者-书有一对多的关系,即一个作者可以写许多书。映射是使用FluentHibernate完成的,它们没有任何特殊之处 我试图询问那些还没有写过书的作者。但是当查看在NHibernate Profiler中生成的查询时,它并不是我所期望的。你们能把这个错误处理掉吗 我期望的结果来自下面的查询 select a.AuthorName ,a.AuthorId from Authors a left outer join Books b on a.Aut
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");
}
}
公共类作者映射:类映射
{
公共作者地图()
{
表(“作者”);
懒散的负荷();
Id(x=>x.AuthorId).GeneratedBy.Identity()列(“AuthorId”);
Map(x=>x.AuthorName).Column(“AuthorName”).Not.Nullable();
Map(x=>x.CreatedAt).Column(“CreateDatetime”).Not.Nullable();
有很多(x=>x.Books);
}
}
上面是为作者提供的映射,下面是为书籍提供的映射
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();
}
}
公共类BooksMap:ClassMap
{
公共图书地图()
{
表(“书籍”);
懒散的负荷();
Id(x=>x.BookId).GeneratedBy.Identity()列(“BookId”);
引用(x=>x.Author).列(“authord”);
Map(x=>x.BookName).Column(“BookName”).Not.Nullable();
}
}
查询按如下方式调用
Session.Linq<Author>().Where(author => author.Books == null).ToList();
Session.Linq().Where(author=>author.Books==null.ToList();
上面的另一种风格导致了对象引用错误
Session.Linq<Author>().Where(author => author.Books.Count == 0).ToList();
Session.Linq().Where(author=>author.Books.Count==0.ToList();
性能问题:
@Ocelot20的答案有效,但正在生成N+1查询以查找记录
Session.Linq().Where(author=>!author.Books.Any()0.ToList()代码>
榜样
作者1、2、3没有书籍,则在执行任何()时运行以下查询
从AuthorId=1的书籍中选择AuthorId、BookId、BookName
从AuthorId=2的书籍中选择AuthorId、BookId、BookName
从AuthorId=3的书籍中选择AuthorId、BookId、BookName
这是怎么发生的 这有用吗
Session.Linq<Author>().Where(author => !author.Books.Any()).ToList()
Session.Linq().Where(author=>!author.Books.Any()).ToList()
我明白了为什么author.Books==null
不起作用,因为它应该是一个空集合,而不仅仅是完全为null。不过我对nhibernate不是很熟悉,所以我不能对配置发表评论。这就是我使用Linq编写查询的方法。在这种情况下,我建议使用子查询而不是JOIN。原因是,一旦我们需要切换查询以找出拥有一些书籍的作者,联接将乘以结果集(拥有两本书籍的作者将被列出两次等)
另外,让我们将NHibernate本机Linq提供程序语法与Query
扩展一起使用(返回requiredIQueryable
)
实现这一点的语法是:
次选择:
var subquery = session.Query<Book>()
.Select(b => b.Author.AuthorId)
;
var subquery=session.Query()
.Select(b=>b.Author.authord)
;
没有任何书籍的一组作者
var list = session.Query<Author>()
.Where(a => !subquery.Contains(a.AuthorId))
;
var list=session.Query()
.Where(a=>!subquery.Contains(a.AuthorId))
;
如果我们想要获得拥有一些书籍的作者列表,我们可以删除NOT操作符(!)并应用分页(Take()
,Skip()
),这将返回正确的结果,而不是成倍的结果。这很有效,但是。它的性能最低。我正在编辑我的问题,以包括如果我实现Any()
@Deeptechtons会发生什么:一些快速的谷歌搜索似乎表明,在nhibernate中,您需要在映射中使用某种fetch
设置,以指示在这种情况下它应该使用联接。