NHibernate で 1 対多としてマップされた IList に新しいオブジェクトを追加するにはどうすればよいですか?
-
12-09-2019 - |
質問
私のモデルにはクラスが含まれています 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
s、それらの詳細を更新することもできます。ただし、新しいものを追加する方法が見つからないようです Static
から Section
, 、この変更をデータベースに永続化します。次のいくつかの組み合わせを試してみました。
mySection.Statics.Add(myStatic)
session.Update(mySection)
session.Save(myStatic)
しかし、(最初の 2 つのステートメントを使用して) 私が得た最も近いものは、次のような SQL 例外です。「値 NULL を列 'Position' に挿入できません。」明らかに INSERT
ここで試みられていますが、Hibernate はインデックス位置を SQL ステートメントに自動的に追加しないようです。
私の何が間違っているのでしょうか?マッピングに何かが欠けているのでしょうか?暴露する必要がありますか? Position
列をプロパティとして作成し、自分で値を割り当てますか?
編集: を削除すると、どうやらすべてが期待どおりに機能します NOT NULL
の制約 Static.Position
データベース内の列。NHibernate が挿入を行い、その直後に行を更新すると思います。 Position
価値。
これは質問に対する答えですが、それが最良のものであるかどうかはわかりません。私は、 Position
そのため、NHibernate がその列の値を直接その列に提供できるようにする何らかの方法があることを願っています。 INSERT
声明。
したがって、質問はまだ未解決です。他に解決策はありますか?
解決
端部の一方は、「逆」でなければなりません。それは、不要なSQL文を回避し、id列は「ヌルではない」ことを可能にするため、ベストプラクティスは、逆のようにコレクションと終わりを設定することです。
ドキュメンテーションあなたのセクション6.4 には次の注意を見つけることができます:
非常に重要な注意:関連の列はNOT NULLと宣言されている場合は、作成または関連付けを更新したときに、NHibernateのは、制約違反が発生することがあります。この問題を回避するには、逆=「真」としてマークされ、多くの大切なエンド(セットまたは袋)との双方向の関連付けを使用する必要があります。この章で後述する双方向関連の説明を参照してください。
だから、あなたはSectionMapであなたのhasManyのマッピングに.Inverseを()を追加する必要があります。
public SectionMap()
{
Id(x => x.Id);
HasMany(x => x.Statics)
.Cascade.All()
.LazyLoad()
.Inverse()
.AsList(x => x.WithColumn("Position"));
}
また、おそらく追加をしたいと設定のセクション、上のメソッドを削除します/独自のコレクションへ/から静的を追加/削除するだけでなく、静的の参照をリセットします:
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可能にする必要があることを意味するかもしれません、代わりに双方向の一方向の関係を使用することを検討して、問題が発生した場合。そうしないとあなたはバッグとしてあなたのコレクションをマッピングするか、リストの代わりに設定する必要があります。
他のヒント
あなたが「セクションID」と呼ばれるフィールドまたは類似した何かを持っている静的のテーブルで。 このフィールドがNULL可能とする:NHibernateのは、最初に参照IDを更新し、その後、新しいレコードを追加します。
。 NHは、データベースレベルで適切なテーブル参照を好きではない理由:?私のデシベルで、私はあまりにも驚いていることを私が発見しました
私はあなたの問題を解決するために探してここに来た理由だけで、私の$ 0.02投げるだろうと思って、答えのどれも実際に動作していないようです。
あなたは溶液中でほとんどがあります。 hasManyのためのあなたのマッピングが正しいです。あなたは、ポジションがデータベースに更新されないと述べてきたような問題は、ある(;私にはそれが本当に働いていない、NULLがDBに挿入されますので、あなたはそれがnullに設定されている場合FWIWを、それだけで「作品」) )。
私は、あなたもあなたの静的クラス上の位置をマップする必要がある、と明らかに静的に位置プロパティが含まれ、それは少し奇妙見つけます。あなたはそれの値が静的リストにある場合によって決定されるため、Positionプロパティは、しかし書き込み可能にしたくありません。
静的に以下を追加します。
public virtual int Position
{
get
{
// Will throw exception if Section is null
// or Section.Statics is null...
return Section.Statics.IndexOf(this);
}
protected set
{
}
}
DBにおける位置欄のそれとは(あなたのStaticMapで自分の位置をマッピングするために覚えている)に更新されます。
私は、静的のNHibプロキシは、それがリストに(私が持っているよりも、いくつかの魔法の大きい)、その後、DBに保存されますという立場だに応じて、位置フィールドを更新することができます推測してます。