2009-07-19 14 views
1

NHibernateにモデルのサブクラスの余分なプロパティを無視させる方法を教えてください。No persister for ... {SUBCLASS} NHibernate with Fluent NHibernate

class SuperModel { // hot I know 
{ 
    public Guid Id { get; private set; } 
    public string FirstName { get; set; } 
} 

class SubModel : SuperModel { 
    public string FavoriteColor { get; set; } 
} 

私は本当に私のリポジトリを使用してSuperModelデータを保存し、他の場所でFavoriteColorを使用する場合にのみ、私は、私は

void Store(SuperModel model) { 
    using (var session = Session){ 
     session.SaveOrUpdate(model); // <<<< The exception is thrown here 
    } 
} 
としての私のリポジトリでそれを保存していても

No persister for: SubModel 

を取得

と他に私が使用しているもの

void WhatToDo(SubModel model) { 
    doSomething(model.FavoriteColor); 
} 

そして、私はそのような

var model = new SubModel { FirstName = "Miranda", FavoriteColor = "Green" }; 
modelRepository.Store(model); 
someService.WhatToDo(model); 

どれ一つとして使用し、私は流暢にこれを設定する方法を知っていますか?ありがとう。

FYI暗黙的キャストと明示キャストは効果がありません。

編集

私のマッピングが、私はこれを行うことができることが分かった2

は、私が理解これ

class SuperModelMap : ClassMap<SuperModel> 
{ 
    public SuperModelMap() 
    { 
     WithTable("SuperModels"); 
     Id(x => x.Id); 
     Map(x => x.FirstName); 
    } 
} 

編集/似ていますが、私のデータベースでは、私がしなければなりませんダミーのテーブルがありますが、これはちょうど非効率です。それは動作しますが、より良い方法がなければならない...私のSuperModelMapで

...

JoinedSubClass<SubModel>("SubModel", MapSubModel); 

private void MapSubModel(JoinedSubClassPart<SubModel> part) 
{ 
    // Leave this empty 
} 

編集3 私は近いんだけど、私はまだ選択に別のエラーを取得します。

私はこれを試しました。

DiscriminateSubClassesOnColumn("Id") 
    .SubClass<SubModel>(m => { }); 

のInnerException { "IDを持つオブジェクト: 5586b075-47f1-49c8-871c-9c4d013f7220 は、指定されたサブクラスではありませんでした: スーパーユーザー(弁別た: '1000')"}のSystem.Exception は{} NHibernate.WrongClassException

+0

マッピングを表示することはできますか? –

+0

私の問題を解決しようとしていました。私はちょうど話としてコードを読んで、笑いを止めることができなかったページの残りの部分全体のために "ホット私が知っている"のコメントの後にええ。学習のための良い固体テストケース:) – percent20

+0

@ percent20 - 投票してください! –

答えて

1

NHibernateのは、あなたが存続するとまったく同じオブジェクトを取得したいということを前提としています。したがって、追加のプロパティについて気にしなくても、オブジェクトの種類に注意する必要があります。そうでない場合、最も簡単な解決策は、SubModelオブジェクトの浅いコピーを作成することですが、SubModelオブジェクトを作成する代わりに、SuperModelオブジェクトを作成します。

あなたはこれについて考えて、それが気に入らないと思います。あなたはダミーのテーブルを避けたいのですが、ダミーの列と一緒に暮らすことができる場合、私はあなたが呼び出すことをお勧めしたい:

DiscriminateSubClassesOnColumn("dummycolumn") 
.SubClass<SubModel>(m => { }); 

この列には、永続オブジェクトの型に関する情報を格納するためにNHibernateによって使用されます。 dbからオブジェクトをロードすると、そのオブジェクトを永続化したときの状態に応じて、SubModelまたはSuperModelになります。

NHibernateがid列に基づいて使用するクラスを決定できなかったため、DiscriminateSubClassesOnColumnを呼び出すソリューションが機能しませんでした。

もう一つのアイデア:私はそれが動作するかどうかわからないんだけど、あなたは、サブモデルのために、スーパーモデルの場合と全く同じことを別のマッピングを追加することができます。次に、NHibernateはSubModelをSuperModelと同じテーブルに保持する必要があります。オブジェクトを要求するとSuperModelオブジェクトを取得する必要があります。残念ながら、私は今このソリューションをテストすることはできません。おそらくあなたはそれを動作させることができます。このソリューションのサブクラスはありません - 2つの "並列"マッピング。

+0

私は検索しようとしたときにそれが好きではありませんでした。 –

+0

申し訳ありませんが、動作するようになりましたが、現在はSubModelを返します。それを止める方法はありますか? –

+0

アイデアは有効ですが、再利用はできません。 –

4

このソリューションを改良して、再利用性を高めることができます。私が理解しているように、あなたは写像の写像が好きではありません。これは避けることができます。

私は、拡張メソッドが含まれているSuperModelMapHelperクラスを作成しました:

public static class SuperModelMapHelper 
{ 
    public static void MapSuperModel<T>(this ClassMap<T> classMap) 
     where T : SuperModel 
    { 
     classMap.WithTable("SuperModels"); 
     classMap.Id(x => x.Id); 
     classMap.Map(x => x.FirstName); 
    } 
} 

あなたが見ることができるように - それはジェネリックだとスーパーモデルのサブクラスのいずれかを受け入れます。次に、2つのマッピングがあります。私はFluentNHibernateの慣習を維持するために拡張メソッドを使用しました

public class SuperModelMap : ClassMap<SuperModel> 
{ 
    public SuperModelMap() 
    { 
     MapSuperModel(); 
    } 
} 

public class SubModelMap : ClassMap<SubModel> 
{ 
    public SubModelMap() 
    { 
     MapSuperModel(); 
    } 
} 

、あなたはそれ単純な静的メソッドにすると、パラメータとしてクラスマップを渡すことができます。

そして、このコード:意図したとおりに

Guid id; 
using (var session = sf.OpenSession()) 
using (var transaction = session.BeginTransaction()) 
{ 
    var subModel = new SubModel() 
         {FavoriteColor = "blue", FirstName = "Jane"}; 
    session.Save(subModel); 
    id = subModel.Id; 
    transaction.Commit(); 
} 

using (var session = sf.OpenSession()) 
using (var transaction = session.BeginTransaction()) 
{ 
    var superModel = session.Get<SuperModel>(id); 
    Console.WriteLine(superModel.GetType().Name); 
    Console.WriteLine(superModel.FirstName); 
    transaction.Commit(); 
} 

ワークス - タイプがスーパークラスです。私はセカンドセッションを作成したことに注意してください。 NHibernateはクエリーの実行を延期するため、保存した同じセッションでエンティティをロードしようとする前に、セッションをフラッシュする必要があります。

このソリューションを使用すると、重複はほとんどありません。 FluentNHibernateのAutoMapping機能を調査して、それをさらに減らすことができます。おそらく独自のコンベンションを作成することで、自動的にそのようなクラスをマッピングすることができます。