【问题标题】:NHibernate How do I query against an IList<string> property?NHibernate 如何查询 IList<string> 属性?
【发布时间】:2009-07-30 21:07:19
【问题描述】:

我正在尝试使用 NHibernate 查询我的一个域类上的 IList 属性。下面是一个简单的例子来演示:

public class Demo
{
    public Demo()
    {
        this.Tags = new List<string>();
    }
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<string> Tags { get; set; }
}

像这样映射:

<class name="Demo">
<id name="Id" />
<property name="Name" />
<bag name="Tags">
  <key column="DemoId"/>
  <element column="Tag" type="String" />
</bag>

而且我能够很好地保存和检索。现在查询我的域类的实例,其中 Tags 属性包含指定值:

var demos = this.session.CreateCriteria<Demo>()
            .CreateAlias("Tags", "t")
            .Add(Restrictions.Eq("t", "a"))
            .List<Demo>();

导致错误:集合不是关联:Demo.Tags

var demos = (from d in this.session.Linq<Demo>()
                     where d.Tags.Contains("a")
                     select d).ToList();

导致错误:未将对象引用设置为对象的实例。

var demos = this.session.CreateQuery("from Demo d where :t in elements(d.Tags)")
            .SetParameter("t", "a")
            .List<Demo>();

工作正常,但由于我真正的域类有很多属性,而且我正在构建一个复杂的动态查询,所以做丑陋的字符串操作不是我的第一选择。我更愿意使用 ICriteria 或 Linq。我有一个用户界面,可以在其中输入许多不同的可能搜索条件。现在构建 ICriteria 的代码有几十行。我真的不想把它变成 HQL 字符串操作。

【问题讨论】:

    标签: c# linq nhibernate hql icriteria


    【解决方案1】:

    因此,由于 Criteria API 的限制,我决定调整我的域类以适应。

    我为标签创建了一个实体类。我什至无法将它创建为值对象。它必须有自己的 id。

    我现在觉得很脏。但对我而言,能够在不使用字符串操作的情况下构建动态查询比忠于领域更重要。

    【讨论】:

    • 有一种方法可以通过标准 api 做到这一点。我把它打包在一个单独的答案中。
    【解决方案2】:

    如此处所述:

    17.1.4.1. Alias and property references

    我们可以使用:

    ...
    A collection key             {[aliasname].key}      ORGID as {coll.key}
    The id of an collection      {[aliasname].id}       EMPID as {coll.id}
    The element of an collection {[aliasname].element}  XID as {coll.element}
    ...
    

    文档中有一个小错误...我们必须使用 ".elements"

    而不是 ".element"
    var demos = this.session.CreateCriteria<Demo>()
            .CreateAlias("Tags", "t")
    
            // instead of this
            // .Add(Restrictions.Eq("t", "a"))
    
            // we can use the .elements keyword
            .Add(Restrictions.Eq("t.elements", "a"))
    
            .List<Demo>();
    

    【讨论】:

      【解决方案3】:

      您需要使用 SubCriterias 而不是别名。 这应该有效:

      var demos = this.session.CreateCriteria<Demo>()
                  .CreateCriteria("Tags")
                  .Add(Restrictions.Eq("Tag", "a"))
                  .List<Demo>();
      

      【讨论】:

      • 这也会导致错误信息:collection was not an association: Demo.Tags
      • 您没有为您的包指定任何表格。我不知道这种映射。这是故意的吗?
      • 如果我指定表名,或者让它使用默认值(在这种情况下与属性名称相同),则没有区别。
      • 好了,终于看到你的问题了。标签是 List,而不是 List。您不能使用 CriteriaAPI 执行此操作。看到这个线程:mail-archive.com/nhibernate-development@googlegroups.com/…
      • 这应该被标记为答案,这是我第一次真正做到了!
      【解决方案4】:

      HQL:

      from Demo d where :val in elements(d.Tags)
      

      【讨论】:

      • 我知道这行得通。以上我承认确实如此。但是我对必须根据用户的输入编写一个巨大的动态查询感到愤怒和尖叫。谢谢你看这个。我很感激奥伦。
      【解决方案5】:

      通过字符串切换到类是一种折衷方案。使用 HQL 而不是 ICriteria 是另一回事。然而,还有第三种妥协……使用自定义 SQL。试试这个。

      var demos = Session.CreateCriteria<Demo>()
          .Add(Expression.Sql(
              "EXISTS (SELECT 1 FROM [Tags] custom_sql_t WHERE custom_sql_t.[DemoId] = {alias}.[Id] AND custom_sql_t.[Tag] = ?)",
              "a",
              NHibernateUtil.String))
          .List<Demo>();
      

      这会导致 NHibernate 2.1.2.4000 生成以下 SQL...

      exec sp_executesql N'SELECT this_.Id as Id2_0_, this_.Version as Version2_0_, this_.Name as Name2_0_ FROM Demo this_ WHERE EXISTS (SELECT 1 FROM [Tags] custom_sql_t WHERE custom_sql_t.[DemoId] = this_.[Id] AND custom_sql_t.[Tag] = @p0)',N'@p0 nvarchar(1)',@p0=N'a'
      

      有关另一个示例,请参阅此帖子...

      NHibernate - Querying from a collection of Value Types (non-Entity) to solve Select N+1

      【讨论】:

        【解决方案6】:

        这可以通过创建一个单独的标准来实现:

        ICriteria demoCriteria = session.CreateCriteria<Demo>();
        ...
        demoCriteria.Add(Restrictions...);
        ...
        ICriteria tagCriteria = demoCriteria.CreateCriteria("Tags");
        tagCriteria.Add(Restrictions.In("elements", new {"Tag1", "Tag2", ...}));
        
        return demoCriteria.List<Demo>();
        

        【讨论】:

          猜你喜欢
          • 2012-03-27
          • 1970-01-01
          • 2010-09-27
          • 1970-01-01
          • 2011-04-30
          • 2012-02-27
          • 2023-04-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多