代码之家  ›  专栏  ›  技术社区  ›  madcapnmckay

Nhibernate标签云查询

  •  3
  • madcapnmckay  · 技术社区  · 16 年前

    到目前为止,这对我来说是一场为期两周的战斗,毫无运气(

    让我先说明我的目标。能够搜索标记为“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包的麻烦。

    2 回复  |  直到 8 年前
        1
  •  1
  •   sirrocco    16 年前

    我设法让它这样工作:

    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 }));
    

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

        2
  •  0
  •   Richard B    16 年前

    伊恩,

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