1

Persona に遅延ロードされた s のコレクションがあるモデルがありRegistrationます。私の NHibernate 3.3.3 クエリはJoinQueryOver、そのリレーションとそれ以上のものを使用します。

var reg = Session.QueryOver<Person>()
    .Where(p => p.ID == pid)
    .JoinQueryOver<Registration>(p => p.Registrations)
    .Where(r => r.IsDropped == false)
    .JoinQueryOver<Slot>(r => r.Slot)
    .JoinQueryOver<Position>(s => s.Position)
    .JoinQueryOver<AcademicTerm>(p => p.Term)
    .Where(t => t.ID == currentTerm.ID)
    .SingleOrDefault();

ログには、クエリの予想される SQL が表示され、予想されるPersonインスタンスが取得されますが、Registrations コレクションにアクセスすると、登録の完全なコレクションが (遅延) 読み込まれます。基準を満たす登録の部分的なコレクションにすぎないと思っていました。

前の質問では、逆の問題がありFetch()、クエリに句を追加して修正しました。

JoinQueryOver 条件によって、ルート エンティティが部分的なコレクションを持つようになるのはいつですか? これは理解しておかなければならない気がします。

私の流暢なマッピングPerson:

public class PersonMapping : ClassMap<Person>
{
    public PersonMapping()
    {
        Id(x => x.ID).GeneratedBy.Guid();
        Map(x => x.Username).Length(20).Unique();
        Map(x => x.HashedPassword).Length(Security.HashedPasswordEncodedLength);
        Map(x => x.PasswordSalt).Length(Security.PasswordSaltEncodedLength);
        Map(x => x.LastName).Length(25).Index("FullName");
        Map(x => x.FirstName).Length(20).Index("FullName");
        Map(x => x.StudentID).Length(12).Nullable();
        Map(x => x.EmployeeID).Length(12).Nullable();
        Map(x => x.EmailAddress).Length(72);
        Map(x => x.IsAdmin).Nullable();
        Map(x => x.IsAgencyStaff).Nullable();
        Map(x => x.IsCenterStaff).Nullable();
        Map(x => x.IsFaculty).Nullable();
        Map(x => x.IsRegistrant).Nullable();
        Map(x => x.IsStudent).Nullable();

        Map(x => x.Type);
        Map(x => x.AuthenticationMode);

        HasMany<Registration>(x => x.Registrations).KeyColumn("Registrant_id")
            .LazyLoad()
            .AsBag()
            .Inverse()
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.SaveUpdate();
    }
}

更新 これを私の他の質問(上記のリンク)と比較すると、反対の問題がありLeft.JoinQueryOver、ベースエンティティからコレクションに取得するために a を使用します。ここで試してみたところ、予想される部分コレクションが得られました。(他のケースでは左結合は実際には必要ありません。なぜそこにあるのか覚えていません。)

フェッチされるレコードは、左結合の有無にかかわらず同じですが、NHibernate がコレクションに入力するケースとそうでないケースがあります。私はそれが信頼できる動作だとは思わないので、登録を個別に照会するように戦略を変更しました。

4

1 に答える 1

1

のこの状態QueryOver:

...
.JoinQueryOver<Registration>(p => p.Registrations)
.Where(r => r.IsDropped == false)
...

実際にはPersonの WHERE 句です。つまり、この条件は、そのような が存在するかどうかを決定Personし、少なくとも 1 つがドロップさRegistrationれていないことを示しています。登録コレクションをフィルタリングする方法ではありません。しかし:

NHibernate には、コレクション自体をフィルタリングする2 つの優れた方法があります。これらはwhere句とfilterです。

1.where句

簡単に言うと、常に where 条件として追加される SQL ステートメントを使用して、コレクション マッピングを拡張できます。6.2を参照してください。Collection のマッピング、抽出:

where="arbitrary sql where condition" == (オプション) コレクションを取得または削除するときに使用する任意の SQL WHERE 条件を指定します (コレクションに使用可能なデータのサブセットのみを含める必要がある場合に役立ちます)

したがって、この場合のマッピングは次のとおりです。

HasMany<Registration>(
  ...
  .Where("IsDropped = 0"); // SQL Statement

2.フィルター設定

where句は静的ですが、アセンブリ/マッピングに焼き付けられています...フィルターは、それを動的に行う方法です。想像してみてください。Registrations次はドロップされ、ドロップされないのセットが必要になることがあります。

に変更できるようにしたいと考えています"IsDropped = 0"("IsDropped = 1" より良いシナリオは、カルチャまたは言語によって切り替えることができます)。そして、それがフィルターを適用できる場所です。18.1 を参照してください。NHibernate フィルター

完全な画像を取得するには、以下のリンクを参照してください。

HasMany
  ...
  .ApplyFilter<MyFilter>()

フィルターは次のようになります。

public class MyFilter: FilterDefinition
{
    public MyFilter()
    {
        WithName("dropped")
          .WithCondition("IsDropped == :isDropped")
          .AddParameter("isDropped", NHibernate.NHibernateUtil.Boolean);
    }
}

最後に、セッション全体に対してフィルターを有効にすることができます(クール、すべてのコレクションはそのトランザクション/セッションで同じ方法でフィルター処理され、すべてのコレクションは でマップされますMyFilter)

session.EnableFilter("dropped").SetParameter("isDropped", false);

詳細はこちら:

于 2013-11-14T03:58:49.080 に答える