NHibernate の使用: 3.3.2 Fluent NHibernate: 1.3.0 .NET 4.0
こんにちは、自動マッピング、特にテーブルごとの階層継承の設定を使用して、Fluent NHibernate の (非常に) 単純な参照プロジェクトをまとめようとしています。既存の(作業中の)プロジェクトから構成をコピーしようとしましたが、AutoMapping と継承に関する Fluent Wiki ページの例を実行しましたが、どちらも同じ結果が得られました。table-per-hiarchy で設定した基本クラスは、通常のクラスのように扱われます。
ドメイン モデルは次のようになります。
namespace Tests
{
public abstract class Animal
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int Legs { get; set; }
}
public class Cat : Animal {}
public class Budgie : Animal {}
}
私が言ったように、簡単に、継承を説明するだけです。「脚」はおそらく基本クラスでオーバーライドする必要があることを認識しています:)
AutoMapping 構成は次のようになります。
public class AutoMappingConfig : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
var include = type.IsSubclassOf(typeof(Animal));
Debug.WriteLineIf(include, string.Format("Included {0} in NHibernate mapping.", type));
return include;
}
public override bool IsDiscriminated(Type type)
{
var result = type.In(
(typeof(Cat)),
(typeof(Budgie))
);
return result;
}
}
最後に、構成/セッションの作成は次のようになります。
public static ISession NewSession()
{
var cfg = new AutoMappingConfig();
var map = AutoMap.AssemblyOf<Animal>(cfg)
.IgnoreBase<Animal>();
var dbConfiguration = MsSqlConfiguration.MsSql2008
.ConnectionString(ConfigurationManager.ConnectionStrings["testdb"].ConnectionString);
return Fluently.Configure()
.Mappings(m =>m.AutoMappings.Add(map))
.Database(dbConfiguration)
.BuildSessionFactory()
.OpenSession();
}
それをまとめて、いくつかの新しいレコードを作成しようとします。
[Test]
public void CreateData()
{
var tiddles = new Cat {Name = "Tiddles", Legs = 4};
var kylie = new Budgie {Name = "Kylie", Legs = 2};
using (var transaction = _session.BeginTransaction())
{
_session.Save(tiddles); // exception!
_session.Save(kylie);
transaction.Commit();
}
}
}
エラーは次のとおりです。
NHibernate.Exceptions.GenericADOException : 挿入できませんでした: [Tests.Cat][SQL: INSERT INTO [Cat] (Name, Legs) VALUES (?, ?); SCOPE_IDENTITY() を選択] ----> System.Data.SqlClient.SqlException : 無効なオブジェクト名 'Cat'。
注意すべき点がいくつかあります。
- 「?」SQL プロファイラーで確認すると、入力されています。
- IsDiscriminated(Type type) メソッドにブレークポイントを配置すると、予想される 2 つのタイプ (Cat と Budgie) で呼び出され、毎回 true を返すことがわかります。ただし、SQL は間違ったテーブルに書き込んでおり、識別子列を書き込んでいません。つまり、これらのクラスは差別されていると言われていますが、そのように扱われていません。
- 表の Id 列は、自動インクリメントの ID 列です。
- 正しい動作をトリガーするために基本プロパティ以外のものが必要な場合に備えて、2 つのサブクラスに他のプロパティを追加しようとしました (違いはありません)。
どんな助けでも大歓迎です。私は今、それが明らかなことであると確信していますが、NHibernate についてよく知っている人は誰もいません (LightSpeed は別の問題です)。
わかりましたので、最終的な作業コードは次のようになります。
public class AutoMappingConfig : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
var include = type.IsSubclassOf(typeof(Animal)) || type == typeof (Animal);
Debug.WriteLineIf(include, string.Format("Included {0} in NHibernate mapping.", type));
return include;
}
public override bool IsDiscriminated(Type type)
{
return typeof(Animal).IsAssignableFrom(type);
}
}
public static ISession NewSession()
{
var cfg = new AutoMappingConfig();
var map = AutoMap.AssemblyOf<Animal>(cfg)
.IncludeBase<Animal>();
var dbConfiguration = MsSqlConfiguration.MsSql2008
.ConnectionString(ConfigurationManager.ConnectionStrings["testdb"].ConnectionString);
return Fluently.Configure()
.Mappings(m =>m.AutoMappings.Add(map))
.Database(dbConfiguration)
.BuildSessionFactory()
.OpenSession();
}
そして、すべてが世界でうまくいっています:)
(つまり、3 つのエラーがありました)
ここでの説明は、最初に .IgnoreBase<> の使用について説明しているため、NHibernate はそれ自体でベースをエンティティとして扱わないため、後で抽象レイヤーのスーパータイプを使用するときに .Includebase<> の使用について言及しているため、少し混乱しています。どちらも試してみたが、フィーロの答えがなければうまくいかなかった。