3

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

现在这是怎么发生的!

4

2 回答 2

1

这行得通吗?

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

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

于 2013-11-01T17:26:32.453 回答
1

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

另外,让我们使用 NHibernate 本机 Linq 提供程序语法和Query扩展名(返回 required 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()),这将返回正确的结果,而不是相乘的结果。

于 2013-11-02T04:22:28.253 回答