NHibernate 4プロジェクトにはいくつかのコレクション関係があります。私はオブジェクトモデルをユニットテストし、すべてのコレクションを実行します。ほとんどの場合は問題なく動作しますが、子コレクションが適切にカスケードされて保存されますが、親エンティティをロードしてコレクションプロパティを調べると、子コレクションは空になります。NHibernate 4子コレクションが保存されましたが、再ロードされません。
ここに、省略されたクラスがあります。 GatewayUserは親オブジェクトであり、Studentのコレクションを持ちます。コレクションにはプライベートバッキングプロパティとAddStudent/RemoveStudentメソッドがあります。
さらに複雑です:私はOAuth2ユーザー管理にNHibernate.AspNet.Identityライブラリを使用しています。GatewayUserはIdentityUserから継承しています。これは、次に、ライブラリの内部基本エンティティクラスを継承します。これは、自分のプロジェクトの基本クラスとは異なります。
パブリッククラスGatewayUser:IdentityUser {パブリックGatewayUser(){ }
public virtual string FirstName { get; set; }
// ...More value properties and OAuth stuff omitted
// students associated with this user
private IList<Student> _students = new List<Student>();
public virtual IList<Student> Students
{
get { return new ReadOnlyCollection<Student>(_students); }
}
public virtual GatewayUser AddStudent(Student s)
{
if (_students.Contains(s))
return this;
s.GatewayUser = this;
_students.Add(s);
return this;
}
public virtual GatewayUser RemoveStudent(Student s)
{
if (_students.Contains(s))
{
_students.Remove(s);
}
return this;
}
は、学生がより普通です。私自身のBaseEntityクラスを継承し、多くの値のプロパティと、ProgramApplicationアイテムの独自の子コレクションを持ちます。興味深いことに、このコレクションは節約して読み込みます。それは、GatewayUserで失敗したコレクションと同じ構造(プライベートバッカーなど)を持っています。
ライブラリは内部的にそのクラスをNHiberante.Mapping.ByCode.Conformistクラス(これまでの経験はありません)でマップするので、マッピングが複雑です。 マップするたくさんのクラスとプロパティがあるので、独自のクラスをNHibernateのオートマッピングにマッピングしています。すべてを動作させるために、ライブラリのマッピングヘルパクラスをコピーし、ベースエンティティクラスをbaseEntityToIgnoreというリストに追加するように少し修正しました。私はGatewayUserに準拠したマッピングを作成しなければなりませんでした。なぜなら、それは異なるベースエンティティタイプを持っていて、私のオートマッピングはそれを拾わないからです。
ユニットテストは次のようになります
[Test]
public void GatewayUserCascadesStudents()
{
var u = new GatewayUser() { FirstName = "Mama", LastName = "Bear", UserName = "[email protected]" };
var s1 = new Student() { FirstName = "First", LastName = "Student" };
var s2 = new Student() { FirstName = "Second", LastName = "Student" };
u.AddStudent(s1).AddStudent(s2);
using (var s = NewSession())
using (var tx = s.BeginTransaction())
{
s.Save(u);
tx.Commit();
}
GatewayUser fetched = null;
int count = 0;
using (var s = NewSession())
{
fetched = s.Get<GatewayUser>(u.Id);
count = fetched.Students.Count;
}
Assert.AreEqual(2, count);
}
生成されるSQLは、両方AspNetUsersとGatewayUser(継承関係を反映する)に挿入し、学生に二つのレコードを挿入します。すべての良い。フェッチすると、SELECTは2つのユーザーテーブルを結合し、GatewayUserオブジェクトを取得しますが、Studentsコレクションにアクセスしても、StudentテーブルのSELECTはトリガーされません。しかし、私がLazy(CollectionLazy.NoLazy)へのマッピングを変更すると、熱心にLoad Studentsを選択するSQLがログに表示されますが、コレクションには値が設定されません。 SQLiteからSQL Serverにデータベースを切り替えると、テーブルに生徒のレコードが表示されます。生成されたSQL(NoLazyが適用されている場合)がそれらをフェッチします。だからデータベースの終わりには、ものは正常に見えます。
私はフランケンシュタインのマッピング状況を非難する必要があると思います。ライブラリのconformistマッピングとFluentマッピングを混在させています.2つの異なる基本エンティティクラスがあります。しかし、生成されたスキーマは正しく見え、セーブカスケードが正しく行われているので、それが問題かどうかはわかりません。