到目前为止,这对我来说已经是 2 周的战斗,没有运气。:(
先说一下我的目的。能够搜索标记为“foo”和“bar”的实体。不会觉得太难了吧?
我知道这可以使用 HQL 轻松完成,但因为这是一个动态构建的搜索查询,不是一个选项。首先是一些代码:
public class Foo
{
public virtual int Id { get;set; }
public virtual IList<Tag> Tags { get;set; }
}
public class Tag
{
public virtual int Id { get;set; }
public virtual string Text { get;set; }
}
映射为多对多,因为 Tag 类用于许多不同的类型。因此没有双向参考。
所以我使用抽象过滤器类建立我的分离标准。让我们假设为简单起见,我只是在搜索带有标签“Apples”(TagId1)&&“Oranges”(TagId3)的Foos,这看起来像。
SQL:
SELECT ft.FooId
FROM Foo_Tags ft
WHERE ft.TagId IN (1, 3)
GROUP BY ft.FooId
HAVING COUNT(DISTINCT ft.TagId) = 2; /*Number of items we are looking for*/
标准
var idsIn = new List<int>() {1, 3};
var dc = DetachedCriteria.For(typeof(Foo), "f").
.CreateCriteria("Tags", "t")
.Add(Restrictions.InG("t.Id", idsIn))
.SetProjection( Projections.ProjectionList()
.Add(Projections.Property("f.Id"))
.Add(Projections.RowCount(), "RowCount")
.Add(Projections.GroupProperty("f.Id")))
.ProjectionCriteria.Add(Restrictions.Eq("RowCount", idsIn.Count));
}
var c = Session.CreateCriteria(typeof(Foo)).Add(Subqueries.PropertyIn("Id", dc))
基本上,这是创建一个 DC,该 DC 投射具有指定所有标签的 Foo Id 列表。
这在 NH 2.0.1 中编译但没有工作,因为它抱怨找不到类 Foo 的属性“RowCount”。
读完这篇文章后,我希望这可能会在 2.1.0 中得到修复,所以我升级了。令我极度失望的是,我发现 ProjectionCriteria 已从 DetachedCriteria 中删除,我无法弄清楚如何在没有 DetachedCriteria 的情况下使动态查询构建工作。
所以我试图思考如何在不需要臭名昭著的Having 子句的情况下编写相同的查询。可以通过标签表上的多个连接来完成。万岁,我认为这很简单。所以我把它改写成这样。
var idsIn = new List<int>() {1, 3};
var dc = DetachedCriteria.For(typeof(Foo), "f").
.CreateCriteria("Tags", "t1").Add(Restrictions.Eq("t1.Id", idsIn[0]))
.CreateCriteria("Tags", "t2").Add(Restrictions.Eq("t2.Id", idsIn[1]))
徒劳地尝试产生下面的sql来完成这项工作(我意识到它不太正确)。
SELECT f.Id
FROM Foo f
JOIN Foo_Tags ft1
ON ft1.FooId = f.Id
AND ft1.TagId = 1
JOIN Foo_Tags ft2
ON ft2.FooId = f.Id
AND ft2.TagId = 3
不幸的是,我在这次尝试中遇到了第一个障碍,收到了“重复关联路径”异常。阅读这似乎是一个古老且仍然非常真实的错误/限制。
我错过了什么?
我开始诅咒 NHibernates 的名字,让你认为什么是你认为如此简单和常见的查询,如此困难。请帮助任何曾经这样做过的人。你是如何绕过 NHibernates 限制的。
忘记声誉和赏金。如果有人在这方面对我有帮助,我会寄给你一个 6 包来解决你的麻烦。