我如何使用Fluent NHibernate自动映射与实体中的同一类型的多个列表? [英] How can I use Fluent NHibernate Automapping with multiple Lists of the same type in an Entity?

查看:135
本文介绍了我如何使用Fluent NHibernate自动映射与实体中的同一类型的多个列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看来,NHibernate不能自动映射一个实体中给定类型的多个IList。



考虑以下两个实体(基于Fluent NHibernate源代码中包含的Examples.FirstProject示例代码)。

  public class Employee 
{
public virtual int Id {get;私人设置}
公共虚拟字符串名字{get;组; }
public virtual string LastName {get;组; }
}

public class Store
{
public virtual int Id {get;私人设置}
公共虚拟IList<员工>工作人员{get;组; }
公共虚拟IList<员工>经理{get;组; }



$ b

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

但是当我自动映射时,Staff和Managers列表存储在Employee表中,全部使用相同的外键。

 员工表

名字姓氏商店名称
3雏菊哈里森1
4杰克托兰斯1
5 Sue Walkers 1
6 Tom Tommorow 1
7 Dick Diggler 1



<最后的结果是,当数据从数据库中读回来时,Staff和Managers列表在表中填入每行行。

这看起来像Automapping中的一个bug,但对于NHibernate来说,我对任何形式都是相当陌生的,并不完全知道它的局限性。

无论如何,我怎样才能让NHibernate将两个列表视为不同?



如果可能的话,我会欣赏一个Automapping代码片段,它直接处理我提供的示例代码(例如,像把这个确切的重写放在你的CreateSessionFactory的.Mappings部分)。

这是因为我对Automapping只有一些熟悉,而且完全不熟悉旧的做事方式,这意味着我不能填写空白非常好。

但是,如果您只有时间指向正确的方向,那也是有帮助的。



下面是我的CreateSessionFactory代码,给出了一些上下文:

prerivate $ ISessionFactory CreateSessionFactory
{
ISessionFactory sessionFactory = null;

const string autoMapExportDir =AutoMapExport;
if(!Directory.Exists(autoMapExportDir))
Directory.CreateDirectory(autoMapExportDir);
$ b $ try
{
var autoPersistenceModel =
AutoMap.AssemblyOf< Product>()
.Where(t => t.Namespace == Example.FirstProject.Entities)
.Conventions.Add(DefaultCascade.All())
;
$ b sessionFactory =流利的.Configure()
。数据库(SQLiteConfiguration.Standard
.UsingFile(DbFile)
.ShowSql()

.Mappings(m => m.AutoMappings.Add(autoPersistenceModel)
.ExportTo(autoMapExportDir)

.ExposeConfiguration(BuildSchema)
.BuildSessionFactory()
;

catch(Exception e)
{
Console.WriteLine(e);
}

return sessionFactory;


解决方案

Paul Batum回答了我的问题<并且提供了一个独立的工作示例, 在这里(点击下载按钮,导航到链接的页面之后),然后点击下载按钮, 。

下面的代码是从他的答案中复制的。关键点在于列表结尾处的StoreMap类,它使用Employee中的IsManager属性设置了一个Where子句。



请注意(至少与1.0.0.594版本一样),Automapping有一个大问题 - 映射类(例如StoreMap)不能和域类(例如Store)在同一个Namespace中!



否则,NHibernate会抛出NHibernate.MappingException:
(XmlDocument)(2,4):XML验证错误:...

绝对没有任何迹象表明真正的问题在哪里。

这可能是一个在Fluent NHibernate的后续版本中可能会修复的错误。

  public class Employee 
{
public virtual int Id {get;私人设置}
公共虚拟字符串名字{get;组; }
public virtual string LastName {get;组; }
public virtual bool IsManager {get;组; }
}


public class Store
{
public virtual int Id {get;私人设置}
公共虚拟IList<员工>工作人员{get;私人设置}
公共虚拟IList<员工>经理{get;私人设置}

$ b $ public Store()
{
Staff = new List< Employee>();
经理=新列表< Employee>();


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


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



$ b $ / code $ / pre
$ b $ p

这里是映射覆盖存储:

  //必须位于Store Store的不同命名空间中! 
公共类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));
}
}


It appears that NHibernate cannot automap more than one IList of a given type in an entity.

Consider the following two entities (based on the Examples.FirstProject sample code that is included with the Fluent NHibernate source code).

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; }
}

This seems to be a perfectly valid object model - each store has several staff employees and several manager employees.

But when I automap, the Staff and Managers lists are stored in the Employee table,all with the same foreign key.

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 

The net result is that when the data is read back out of the database, both Staff and Managers lists are populated with every row in the table.

This looks like a bug in Automapping to me, but I'm fairly new to NHibernate in any form, and don't fully know it's limitations yet.

In any case, how can I make NHibernate treat the two lists as distinct?

If possible, I'd appreciate an Automapping code fragment that directly addresses the sample code I've provided (e.g. something like "put this exact override in the .Mappings section of your CreateSessionFactory").

This is because I'm only somewhat familiar with Automapping, and not at all familiar with the older ways of doing things, which means I can't "fill in the blanks" very well yet.

But if you only have time to point me in the right direction, that would be helpful too.

Here's my CreateSessionFactory code, to give some context:

    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;
    }

解决方案

Paul Batum answered my question here, and provided a standalone working example here (click the Download button after you navigate to the linked page).

The following code is copied from his answer. The key point is in the StoreMap class at the end of the listing, which sets up an override with a Where clause that uses the IsManager property in Employee.

Note that (at least with v. 1.0.0.594) there is one big gotcha with Automapping - the mapping class (e.g. StoreMap) cannot be in the same Namespace as the domain class (e.g. Store)!

Otherwise, NHibernate will throw "NHibernate.MappingException: (XmlDocument)(2,4): XML validation error: ..." , with absolutely no indication of what or where the real problem is.

This is probably a bug that may be fixed in later versions of 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); 
    } 


} 

Here is the mapping override for store:

// 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)"); 
   } 
} 

这篇关于我如何使用Fluent NHibernate自动映射与实体中的同一类型的多个列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆