6

NHibernate は、エンティティ内の特定のタイプの複数の IList を自動マップできないようです。

次の 2 つのエンティティを検討してください (Fluent NHibernate ソース コードに含まれている Examples.FirstProject サンプル コードに基づく)。

public class Employee
{
    public virtual int Id { get; private set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
}

public class Store
{
    public virtual int Id { get; private set; }
    public virtual IList<Employee> Staff { get; set; }
    public virtual IList<Employee> Managers { get; set; }
}

これは完全に有効なオブジェクト モデルのように思われます。各店舗には数人の従業員と管理職がいます。

しかし、自動マップすると、Staff と Managers のリストが Employee テーブルに格納され、すべて同じ外部キーが使用されます。

Employee Table

Id FirstName LastName Store_id 
3  Daisy     Harrison   1 
4  Jack      Torrance   1 
5  Sue       Walkters   1 
6  Tom       Tommorow   1 
7  Dick      Diggler    1 

最終的な結果として、データがデータベースから読み戻されると、Staff リストと Managers リストの両方にテーブルのすべての行が取り込まれます。

これは私には Automapping のバグのように見えますが、私はどのような形であれ NHibernate にかなり慣れていないため、それが制限であることをまだ完全には知りません。

いずれにせよ、NHibernate に 2 つのリストを別個のものとして扱わせるにはどうすればよいでしょうか?

可能であれば、私が提供したサンプル コードに直接対応する Automapping コード フラグメントをいただければ幸いです (たとえば、「この正確なオーバーライドを CreateSessionFactory の .Mappings セクションに入れる」など)。

これは、私が Automapping にある程度慣れているだけで、古い方法にはまったく慣れていないためです。つまり、まだ「空白を埋める」ことができていません。

しかし、私を正しい方向に向ける時間があれば、それも役に立ちます.

いくつかのコンテキストを提供するために、これが私の CreateSessionFactory コードです。

    private static ISessionFactory CreateSessionFactory()
    {
        ISessionFactory sessionFactory = null;

        const string autoMapExportDir = "AutoMapExport";
        if( !Directory.Exists(autoMapExportDir) )
            Directory.CreateDirectory(autoMapExportDir);

        try
        {
            var autoPersistenceModel = 
                AutoMap.AssemblyOf<Product>()
                        .Where(t => t.Namespace == "Examples.FirstProject.Entities")
                        .Conventions.Add( DefaultCascade.All() )
                ;

            sessionFactory = Fluently.Configure()
                .Database(SQLiteConfiguration.Standard
                              .UsingFile(DbFile)
                              .ShowSql()
                         )
                .Mappings(m => m.AutoMappings.Add(autoPersistenceModel)
                                             .ExportTo(autoMapExportDir)
                         )
                .ExposeConfiguration(BuildSchema)
                .BuildSessionFactory()
                ;
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

        return sessionFactory;
    }
4

1 に答える 1

5

Paul Batum はここで私の質問に答え、スタンドアロンの動作例をここで提供しました(リンク先のページに移動した後、[ダウンロード] ボタンをクリックしてください)。

次のコードは、彼の回答からコピーされたものです。重要な点は、リストの最後にある StoreMap クラスにあります。これは、Employee の IsManager プロパティを使用する Where 句でオーバーライドを設定します。

(少なくとも v. 1.0.0.594 では) Automapping には大きな落とし穴が 1 つあります。マッピング クラス (StoreMap など) は、ドメイン クラス (Store など) と同じ Namespace にすることはできません。

それ以外の場合、NHibernate は"NHibernate.MappingException: (XmlDocument)(2,4): XML validation error: ..."をスローし、実際の問題が何であるか、またはどこにあるかをまったく示しません。

これはおそらくバグであり、Fluent NHibernate の以降のバージョンで修正される可能性があります。

public class Employee 
{ 
    public virtual int Id { get; private set; } 
    public virtual string FirstName { get; set; } 
    public virtual string LastName { get; set; } 
    public virtual bool IsManager { get; set; } 
} 


public class Store 
{ 
    public virtual int Id { get; private set; } 
    public virtual IList<Employee> Staff { get; private set; } 
    public virtual IList<Employee> Managers { get; private set; } 


    public Store() 
    { 
        Staff = new List<Employee>(); 
        Managers = new List<Employee>(); 
    } 


    public void AddManager(Employee employee) 
    { 
        employee.IsManager = true; 
        this.Managers.Add(employee); 
    } 


    public void AddStaff(Employee employee) 
    { 
        this.Staff.Add(employee); 
    } 


} 

ストアのマッピング オーバーライドは次のとおりです。

// Must be in different Namespace from class Store!!!
public class StoreMap : IAutoMappingOverride<Store> 
{ 
   public void Override(AutoMapping<Store> mapping) 
   { 
       mapping.HasMany(x => x.Managers) 
           .Cascade.All() 
           .Where("(IsManager = 1)"); 
       mapping.HasMany(x => x.Staff) 
           .Cascade.All() 
           .Where("(IsManager = 0)"); 
   } 
} 
于 2009-11-25T21:43:28.147 に答える