-2

これらのドメインオブジェクトを例として取り上げましょう。

public class A 
{
    public Guid Id { get; set; }
    public ICollection<B> CollectionOfB { get; set; }
}

public class B 
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

NHibernate 3.xを使用して、これらの名前Aを持つオブジェクトを取得する必要がありますBname1name2

たとえば、B名前の配列から文字列として取得したいものを取得するとしますstring[] names = new string[] { "name1", "name2" }

私は考えましたが.Query<A>().Where(someA => some.CollectionOfB.Any(someB => names.Contains(someB.Name)))これがNHibernateLINQプロバイダーによってSQLクエリとしてコンパイルされるのではないかと思います。多分これはあまり最適ではないSQLクエリにコンパイルされるでしょう。

NHibernate 3.x LINQプロバイダーを使用してこのクエリを構築する最適な方法は何でしょうか?

4

2 に答える 2

2

あなたが考えたクエリ:

var someAs = session.Query<A>().Where(someA => some.CollectionOfB.Any(someB => names.Contains(someB.Name)));

正常に動作します。同様の構造でテストしました。NHibernateは、IN句を含む相関サブクエリを発行します。

[編集]あなたのコメントに関しては、クエリの意図がコードから明確であるという意味で最適です。パフォーマンスを測定する必要があり、データベースエンジンは、見苦しいクエリを非常に効率的なクエリに変換できるクエリオプティマイザを使用するため、多くの場合と同様に、クエリの外観を判断することはできません。

サンプルクエリを内部結合を使用するように変更し、より良い実行プランを取得しました(ソート操作が不要になりました)。LINQクエリ構文を使用してクエリを書き直すと、より適切な実行プランが使用されますが、クエリに内部結合が含まれていません。代わりに、where句で古いスタイルの結合を使用します。

var someAs = (from someA in session.Query<A>()
              join someB in session.Query<B>() on someA.Id equals someB.A_Id
              where names.Contains(someB.Name)
              select someA).ToArray();
于 2013-01-07T15:03:54.247 に答える
0

クラスBを拡張してAへの参照を持つ場合:

public class B 
{
    public A A {get;set;}
    public Guid Id { get; set; }
    public string Name { get; set; }
}

次に、次のようにサブクエリを実行します。

var aObjectsToRetrieve = Query<B>().Where(x=>x.Name.StartsWith("name1")).Select(x=>x.A.Id);

次に、AのクエリにExists()を適用して、必要なAオブジェクトを取得します。名前の配列がある場合は、次のようなもの(またはシナリオによっては接続詞)を試すことができます。

  var disjunction = new Disjunction();
  var names = new[] {"name1", "name2"};
  foreach (string name in names)
            disjunction.Add(Restrictions.InsensitiveLike(PropName<User>(x => x.Name), name));
于 2013-01-07T12:32:59.310 に答える