4

私のモデルには、このセクションの一部でSectionある順序付きリストを持つクラスが含まれています。Statics他のすべてのプロパティを除外すると、モデルの実装は次のようになります。

public class Section
{
    public virtual int Id { get; private set; }
    public virtual IList<Static> Statics { get; private set; }
}

public class Static
{
    public virtual int Id { get; private set; }
}

データベースでは、リレーションシップは 1 対多として実装されます。テーブルStatic には、参照先の外部キーと、その一部であるリスト内のインデックス位置を格納するSectionための整数列があります。Position

マッピングは、次のように Fluent NHibernate で行われます。

public SectionMap()
{
    Id(x => x.Id);
    HasMany(x => x.Statics).Cascade.All().LazyLoad()
            .AsList(x => x.WithColumn("Position"));
}

public StaticMap()
{
    Id(x => x.Id);
    References(x => x.Section);
}

これで、既存Staticの をロードできるようになり、それらの詳細を更新することもできます。Staticただし、新しい を に追加し、Sectionこの変更をデータベースに永続化する方法を見つけることができないようです。私はいくつかの組み合わせを試しました:

  • mySection.Statics.Add(myStatic)
  • session.Update(mySection)
  • session.Save(myStatic)

しかし、(最初の2つのステートメントを使用して)得た最も近いものは、SQL例外の読み取りです:「列 'Position'に値NULLを挿入できません」。ここでは明らかに anINSERTが試みられていますが、NHibernate はインデックス位置を SQL ステートメントに自動的に追加していないようです。

私は何を間違っていますか?マッピングに欠けているものはありますか? 列をプロパティとして公開し、Position自分で値を割り当てる必要がありますか?

編集:データベース内NOT NULLの列の制約を削除すると、すべてが期待どおりに機能するようです。Static.Position私はNHibernateが挿入を行い、すぐに行をPosition値で更新すると思います。

これは質問に対する答えですが、それが最良のものかどうかはわかりません。列がnull可能でないことを望んでいるので、NHibernateがステートメントPositionでその列に直接値を提供するようにする方法があることを願っています。INSERT

したがって、質問はまだ開いています。他の解決策はありますか?

4

3 に答える 3

7

NHibernate で双方向の 1 対多の関係を使用する場合、端の 1 つは「逆」でなければなりません。ベスト プラクティスは、コレクションの末尾を逆に設定することです。これにより、不要な SQL ステートメントを回避し、id 列を「非 null」にすることができます。

ドキュメントのセクション 6.4に、次の注記があります。

非常に重要な注意: アソシエーションの列が NOT NULL と宣言されている場合、NHibernate はアソシエーションを作成または更新するときに制約違反を引き起こす可能性があります。この問題を回避するには、inverse="true" としてマークされた多くの値を持つエンド (セットまたはバッグ) との双方向の関連付けを使用する必要があります。この章で後述する双方向関連の説明を参照してください。

したがって、.Inverse() を SectionMap の HasMany マッピングに追加する必要があります。

public SectionMap()
{
    Id(x => x.Id);
    HasMany(x => x.Statics)
        .Cascade.All()
        .LazyLoad()
        .Inverse()
        .AsList(x => x.WithColumn("Position"));
}

また、Section に Add メソッドと Remove メソッドが必要になることもあります。これは、スタティックの参照を設定/リセットし、独自のコレクションにスタティックを追加/削除するだけでなく、次のようにします。

public virtual void AddStatic(Static static)
{
    Statics.Add(static);
    static.Section = this;
}


public virtual void RemoveStatic(Static static)
{
    Statics.Remove(static);
    static.Section = null;
}

これらの方法により、関係の両側で参照が正確に保たれます。

ドキュメントのセクション 6.8によると、インデックス付きコレクションを使用する場合、NHibernate は双方向の関係をサポートしません。

NHibernate は、インデックス付きコレクション (リスト、マップ、または配列) を「多」側として使用する双方向の 1 対多の関連付けをサポートしていないことに注意してください。セットまたはバッグ マッピングを使用する必要があります。

それでも問題が解決しない場合は、双方向の代わりに単方向の関係を使用することを検討してください。ただし、それは外部キー列を null 可能にする必要があることを意味する可能性があります (投稿の冒頭のメモによると)。そうしないと、コレクションをリストではなくバッグまたはセットとしてマップする必要がある場合があります。

于 2009-08-10T08:37:07.970 に答える
2

Static のテーブルには、「SectionID」などと呼ばれるフィールドがあります。このフィールドを NULL 可能にします。NHibernate は最初に新しいレコードを追加し、次に参照 ID を更新します。

私は自分のデータベースでそれを発見しましたが、私も驚いています.NHがデータベースレベルで適切なテーブル参照を好まないのはなぜですか?

于 2009-08-10T07:26:18.940 に答える
1

0.02 ドルを投入しようと思ったのは、あなたの問題を解決するためにここに来たのですが、どの回答も実際にはうまくいかないようだったからです。

あなたはあなたの解決策にほぼ到達しています。HasMany のマッピングは正しいです。問題は、あなたが言ったように、Positionがデータベースで更新されないことです(FWIWをnullに設定すると、NULLがDBに挿入されるため、「機能する」だけです;私にとっては、実際には機能していません;) )。

少し奇妙だと思います。静的クラスにも位置をマップする必要があり、明らかに静的に位置プロパティを含める必要があります。ただし、Position プロパティを書き込み可能にしないでください。その値は、Static がリスト内のどこにあるかによって決定されるためです。

以下を静的に追加します

public virtual int Position 
{
    get 
    {
        // Will throw exception if Section is null
        // or Section.Statics is null...
        return Section.Statics.IndexOf(this);
    }
    protected set 
    {
    }
}

これにより、データベースの位置列が更新されます (StaticMap で位置をマッピングすることを忘れないでください)。

StaticのNHibプロキシは、リスト内の位置に応じてPositionフィールドを更新でき(私が所有するよりも大きな魔法によって)、データベースに保存されると思います。

于 2013-01-24T01:18:38.107 に答える