10

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

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 字符串操作。

4

6 回答 6

4

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

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

我现在觉得很脏。但是能够在不诉诸字符串操作的情况下构建动态查询对我来说比忠于领域更重要。

于 2009-07-31T14:13:40.640 回答
4

如此处所述:

17.1.4.1。别名和属性引用

我们可以用:

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

文档中有一个小错误...而不是".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>();
于 2014-11-05T11:14:16.457 回答
3

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

var demos = this.session.CreateCriteria<Demo>()
            .CreateCriteria("Tags")
            .Add(Restrictions.Eq("Tag", "a"))
            .List<Demo>();
于 2009-07-30T21:48:14.160 回答
3

总部:

from Demo d where :val in elements(d.Tags)
于 2009-07-31T01:49:09.190 回答
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>();

这将导致 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 - 从值类型(非实体)的集合中查询以解决 Select N+1

于 2010-10-27T11:36:12.080 回答
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>();
于 2016-12-05T10:31:57.433 回答