3

到目前为止,这对我来说已经是 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 包来解决你的麻烦。

4

2 回答 2

1

我设法让它像这样工作:

var dc = DetachedCriteria.For<Foo>( "f")
            .CreateCriteria("Tags", "t")
            .Add(Restrictions.InG("t.Id", idsIn))
            .SetProjection(Projections.SqlGroupProjection("{alias}.FooId", "{alias}.FooId having count(distinct t1_.TagId) = " + idsIn.Count,
                         new[] { "Id" }, 
                           new IType[] { NHibernateUtil.Int32 }));

这里唯一的问题是计数(t1_ .TagId)——但我认为在这个 DetachedCriteria 中每次都应该生成相同的别名——所以你应该安全地进行硬编码。

于 2009-08-15T18:50:20.597 回答
0

伊恩,

由于我不确定您使用的是什么数据库后端,您能否对生成的 SQL 查询进行某种跟踪并查看 SQL 以找出问题所在?

我知道我过去这样做是为了了解 Linq-2-SQL 和 Linq-2-Entities 是如何工作的,并且能够调整某些情况以改善数据访问,以及了解为什么某些事情没有按最初预期工作。

于 2009-08-15T11:52:09.153 回答