0

NHibernate を使用してコードでマッピングしています。クラスは次のとおりです。

[Serializable]
public class Person : ObjectBase
{
    public virtual IDictionary<AttributeType, Attribute> Attributes { get; set; }
}

そしてここにマッピングがあります:

public class PersonMapping : BaseObjectMapping<Person>
{
    public PersonMapping()
    {
        Map(x => x.Attributes, c =>
        {
            c.Access(Accessor.Property);
            c.Lazy(CollectionLazy.NoLazy);
            c.Cascade(Cascade.All);
            c.Key(k => k.Column("PersonId"));
        }, k => k.Element(m => m.Column("AttributeTypeId")), r => r.OneToMany());
    }
}

問題は、ディクショナリのキーにアクセスしようとすると、キーの種類が AttributeTypeProxy になることです。次に、セッションが存在しなくなったコード領域でキーを遅延ロードしようとするようです。したがって、次のエラーがスローされます: Initializing[AttributeType#1]-Could not initialize proxy - no Session.

そのため、いくつかの調査の後、強制的にロードする必要があると言われました。キー マッピングに関連する .Lazy は表示されません。また、Map の値が熱心に読み込まれることを確認しました (これは CollectionLazy.NoLazy によるものだと思います)。Map の熱心な読み込みのキーを作成するにはどうすればよいですか?


編集:

Rippoの回答に従って属性を適切にロードしないで作成しようとして、Personのマッピングを一時的に変更して属性テーブルを作成しました。

Map(x => x.Attributes, c =>
{
    c.Key(k => k.Column("PersonId"));
    c.Table("Attribute");
}, 
k => k.Element(m => m.Column("AttributeTypeId")), 
r => r.Component(m => m.Property(p => p.Data)));

ここで、彼の例に従ってアクセスしようとすると、次のperson.Attributesエラーが発生します: Initializing[Person#1]-failed to lazily initialize a collection of role: Person.Attributes, no session or session was closed

Rippo は、実際にデータを取得するコードを投稿することも提案しました。私はこれらの方法を使用します:

internal static class RepositoryHelper
{
    public static void PerformDatabaseUpdate(Action<ISession> action)
    {
        using (var session = NHibernateHelper.OpenSession())
        using (var transaction = session.BeginTransaction())
        {
            action(session);
            transaction.Commit();
        }
    }

    public static T PerformDatabaseQuery<T>(Func<ISession, T> action)
    {
        using (var session = NHibernateHelper.OpenSession())
        {
            return action(session);
        }
    }
}

Map を使用して IDictionary をマッピングする前に、これらを使用しても問題はありませんでした。ただし、これまでは、プロパティと ICollections のみを使用していました (Set マッピングを介して)。また、これはクライアント/サーバー アプリケーションに使用されることにも言及する必要があります。クライアントは MVVM WPF アプリケーションで、サーバーはサービスになります (現在は単なるコンソール アプリです)。


編集2:

回避策を見つけましたが、それを答えとは絶対に考えません。また、なぜそれが機能するのかわかりません。私が思いつくことができる唯一の結論は、コードによるマッピングのマップがその仕事をしていないということです。これが私が変更したものです:

[Serializable]
public class Person : ObjectBase
{
    public virtual IDictionary<AttributeType, Attribute> Attributes { get; set; }
    public virtual ICollection<AttributeType> AttributeTypes
    {
        get { return Attributes.Keys; }
        set { }
    }
}

うん。ディクショナリからのキーも保持するために、AttributeType の ICollection を追加しました。属性から実際のキーのみを返すことができます。ただし、NHibernate が適切に使用するには set メソッドが必要です。メソッドには何も入れていません。

次に、これをマッピングに追加しました。

public class PersonMapping : BaseObjectMapping<Person>
{
    public PersonMapping()
    {
        Map(x => x.Attributes, c =>
        {
            c.Access(Accessor.Property);
            c.Lazy(CollectionLazy.NoLazy);
            c.Cascade(Cascade.All);
            c.Key(k => k.Column("PersonId"));
        }, k => k.Element(m => m.Column("AttributeTypeId")), r => r.OneToMany());

        Set(x => x.AttributeTypes, c =>
        {
            c.Table("UnusedAttributeTypes");
            c.Access(Accessor.Property);
            c.Lazy(CollectionLazy.NoLazy);
            c.Key(k => k.Column("PersonId"));
        }, r => r.ManyToMany());
    }
}

これは、PersonId と AttributeTypeId を含む UnusedAttributeTypes というテーブルを作成するだけです。オブジェクト経由でアクセスできないため、これはダミー テーブルです。

今、私が行って呼び出すとperson.Attributes.Keys、それらはプロキシ AttributeType オブジェクトではなく、実際のオブジェクトであり、適切に入力されます。また、person.Attributes.Values以前と同じようにまだ人口が多いです。そこに変更はありません。

NHibernate のソース コードを検索して、これで問題が解決する理由や、実際の問題は何かを調べる必要がないことを願っています。

編集 3 : c.Cascade(Cascade.All); を削除しました。AttributeTypes マッピングから。

4

1 に答える 1