10

NHibernate を使用して、ドメイン クラスの 1 つで 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

ここに文書化されているように:

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 に答える
4

そのため、Criteria API の制限により、ドメイン クラスを適合するように曲げることにしました。

タグのエンティティ クラスを作成しました。値オブジェクトとして作成することさえできませんでした。独自の ID が必要でした。

私は今汚れていると感じています。しかし、私にとっては、ドメインに忠実であり続けることよりも、文字列操作に頼らずに動的クエリを作成できることが重要でした。

于 2009-07-31T14:13:40.640 に答える
3

エイリアスではなく SubCriterias を使用する必要があります。これはうまくいくはずです:

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

HQL:

from Demo d where :val in elements(d.Tags)
于 2009-07-31T01:49:09.190 に答える
2

文字列を介してクラスに切り替えることは、妥協の 1 つです。ICriteria の代わりに HQL を使用することも別の方法です。ただし、3 つ目の妥協点があります... カスタム 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 - Select N+1 を解決するための値型 (非エンティティ) のコレクションからのクエリ

于 2010-10-27T11:36:12.080 に答える