6

似乎 NHibernate 不能在一个实体中自动映射多个给定类型的 IList。

考虑以下两个实体(基于 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; }
}

这似乎是一个完全有效的对象模型——每家商店都有几名员工和几名经理员工。

但是当我自动映射时,员工和经理列表存储在员工表中,都具有相同的外键。

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 将这两个列表视为不同的?

如果可能的话,我会很感激一个自动映射代码片段,它直接解决了我提供的示例代码(例如“将这个确切的覆盖放在你的 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 有一个大问题 -映射类(例如 StoreMap)不能与域类(例如 Store)在同一个命名空间中!

否则,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 回答