NHibernate到Linq得到没有写书的作者

时间:2013-11-01 17:21:12

标签: c# sql linq nhibernate

我以作者和书籍为例,使解释变得简单。作者 - 书籍有一对多关系,即一位作者可以写很多书。映射是使用 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

现在怎么回事!!

2 个答案:

答案 0 :(得分:1)

这有用吗?

Session.Linq<Author>().Where(author => !author.Books.Any()).ToList()

我明白为什么author.Books == null不起作用,因为它应该是一个空集合,而不仅仅是完全为空。我对nhibernate不太熟悉,所以我无法对配置发表评论。这就是我使用Linq编写查询的方式。

答案 1 :(得分:1)

在这种情况下,我建议使用子查询而不是 JOIN 。原因是,一旦我们需要切换查询以查找具有某些书籍的作者,JOIN将乘以结果集(具有2本书的作者将被列出两次等)。

另外,让我们使用带有Query扩展名的NHibernate原生Linq提供程序语法(返回必需的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()),这将返回正确但不会相乘的结果。