到目前为止,这对我来说是一场为期两周的战斗,毫无运气(
让我先说明我的目标。能够搜索标记为“foo”的实体
和
我知道用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; }
}
映射为多对多,因为标记类用于许多不同的类型。因此没有双向参考。
所以我用一个抽象的过滤器类来建立我的分离标准。为了简单起见,假设我只是在搜索带有标记“Apples”(TagId1)的foo&&”橘子”(TagId3)这看起来像。
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来投影一个Foo id列表,其中指定了所有标记。
这是在nh2.0.1中编译的,但由于它抱怨在类Foo上找不到属性“RowCount”,所以无法工作。
读后
this
所以我试着思考如何在不需要臭名昭著的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]))
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
around
ancient
而且还是非常真实的缺陷/限制。
忘记名誉和赏金吧。如果有人帮我一个忙,我会送你一个6包的麻烦。