1

わかりました、私はこのNHibernateクエリに少し困惑しています。混乱はPasswordResetTokenに関するものです。

まず、マッピングは次のとおりです。

public ContactMap()
    {
        Table("Contact");
        Id(x => x.ContactId, "ContactId").Unique().GeneratedBy.Increment();
        Map(x => x.EmailAddress);
        ...
        Map(x => x.JobTitle);

        References(x => x.PasswordResetToken, "EmailAddress")
            .PropertyRef(x => x.EmailAddress)
            .Cascade.None()
            .Not.LazyLoad()
            .Not.Update();


        HasMany(x => x.Roles)
            .Table("tblContactRole").KeyColumn("ContactId").Element("Role", part => part.Type<global::NHibernate.Type.EnumStringType<ContactRoles>>())
            .AsSet()
            .Not.LazyLoad();
    }

ここにクエリがあります:

public IList<Contact> GetContacts(int id)
    {
        var contacts = Session.CreateCriteria<Contact>()
                           .Add(Restrictions.Eq("Id", id))
                           .Add(Restrictions.Eq("IsActive", true))
                           .SetFetchMode("Roles", FetchMode.Eager)
                           .SetFetchMode("PasswordResetToken", FetchMode.Eager)
                           .SetResultTransformer(CriteriaSpecification.DistinctRootEntity)
                           .List<Contact>();

        return contacts;
    }

私の理解では、FetchMode.Eagerは、SUBSELECTの代わりにJOINが使用されることを意味するため、dbへの追加の呼び出しが表示される理由はありません。

NHProfのスクリーンショット(強調表示されたクエリ)から明らかなように、連絡先をハイドレイトするために必要なすべての情報を返す正しいSQLクエリが実行されます(異なるテーブル名などについて心配する必要はありません-上記のコードをサニタイズしました):

NHProf

私が理解していないのは、なぜPasswordResetTokenテーブルへの数十の個別の選択が生成されて実行されるのですか?これらのクエリの1つは、PasswordResetTokenを持たないすべての連絡先に対してのみ生成されます(つまり、最初のクエリはそれらの列に対してnullを返します)-これがそれと何の関係があるのか​​わかりません。

連絡先にはいくつかの役割がある場合とない場合があり(この問題には不要)、同様に、PasswordResetTokenが1つだけある場合とない場合があります。

DBは少し危険で、外部キーがほとんどありません。この場合のContactとPasswordResetTokenの間のリンクは、単純な共有列「EmailAddress」です。

これらのクエリはすべて、上記の1行のコードの実行時に生成されます(つまり、そのコードはループ内にありません)。

情報が不足している場合はお知らせください。

何をグーグルする必要がありますか?

4

1 に答える 1

3

バグです。バグレポートからはそれが難しいように思えますが、2つのクエリで動作するようにしようと思います。

添付のテストは、(Idの代わりに)一意のプロパティを参照する多対1の関連付けにより、選択n+1の問題が発生することを示しています。最初のステートメントには正しい結合が含まれていますが、結合の選択後、関連するすべてのエンティティが1つずつフェッチされます。(一意の列に同じ値を持つエンティティは、複数回フェッチされることもあります。)

興味深い点は、このバグは、参照されるエンティティがすでにセッションキャッシュにある場合にのみ発生することです。そうでない場合、追加のselectステートメントは作成されません。

于 2013-03-20T16:00:21.000 に答える