NHibernate如何查询IList <string>属性?</string>

时间:2009-07-30 21:07:19

标签: c# linq nhibernate hql icriteria

我正在尝试查询IList&lt; string&gt;使用NHibernate在我的一个域类上的属性。这是一个简单的例子来说明:

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

错误结果:Objct引用未设置为对象的实例。

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

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

6 个答案:

答案 0 :(得分:4)

因此,由于Criteria API的限制,我决定将我的域类改为适合。

我为Tag创建了一个实体类。我甚至无法将其创建为值对象。它必须有自己的身份。

我现在觉得很脏。但是,能够构建动态查询而不诉诸字符串操作对我来说比对域保持真实更重要。

答案 1 :(得分:4)

如此处所述:

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}
...

doc中有一个小错误...而不是".element"我们必须使用 ".elements"

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:3)

HQL:

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

答案 4 :(得分:2)

通过字符串切换到类是一种妥协。另一个是使用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>();

这导致后续SQL由NHibernate 2.1.2.4000 ...

生成
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

答案 5 :(得分:0)

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

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