使用映射或模仿Fluent NHibernate的多对多关系的选项?

时间:2013-04-19 16:56:01

标签: c# nhibernate fluent-nhibernate

编辑 - 快速摘要

我意识到我有相当多的文字,所以这里有一个问题的快速摘要:

  • <many-to-any />unsupported by Fluent NHibernate
  • 想要在XML和Fluent之间拆分属性映射以映射<many-to-any />关系
  • 使用named queries
  • 可以找到这一点
  • 当尝试将XML和Fluent用于我的界面时,我得到NHibernateDuplicateMappingException
  • 当尝试仅将XML用于接口而Fluent用于我的子类时,XML映射会将其用于数据库,但忽略Fluent。

由于我定义了大量约定,因此我不希望仅对此类层次结构使用XML。

此外,如果有人知道在Fluent中使用多对多的替代解决方案,我会非常愿意尝试一下。


编辑 - 完整问题和代码示例

我有两个分享多对多关系的课程(我们称之为“Foo”和“Bar”)。通常情况下,使用Fluent进行映射就像在我的类地图中抛出HasManyToMany(x => x.SomeProperty)一样简单;但是,我遇到了一个接口问题。

供参考,以下是对象的基本示例设置:

public class Foo
{
    public virtual long ID { get; set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual IList<IBar> Bars { get; set; }
}

public interface IBar
{
    long ID { get; set; }
    IList<Foo> Foos { get; set; }
}

由于IBar是一个可以附加到几乎任何类的接口,因此在中间表上引用的任何“BarID”都可以属于任意数量的其他表。由于这是一个"many-to-any"关系,它是still unsupported by Fluent(是的,我知道这是由NHibernate的mapping-by-code支持的。)

幸运的是,NHibernate的xml映射仍然可以在使用Fluent的项目中轻松使用。不过,我不想在* .hbm.xml文件中定义整个地图,而只想映射<many-to-any />。其余部分,我想保留在Fluent地图中(基本上,将映射分成两个文件)。

我知道named queries and stored procedures这样的事情是可行的,但我在使用这种模式来定义我的关系时遇到了一些麻烦。

这是我现在的Foo类的Fluent映射:

 
public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Id(x => x.ID);
        Map(x => x.Name);
        Map(x => x.Description);
    }
}

这里是Foo.hbm.xml文件:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyProject" namespace="MyProject.Entities">
    <class name="Foo" table="Foos"> 
        <id name="ID">      
            <generator class="identity" />
        </id>
        <bag name="Bars" table="FooBarRelationship">
            <key column="ID" />
            <many-to-any id-type="System.Int64" meta-type="System.String">
                <column name="BarID" />
                <column name="BarType" />
            </many-to-any>
        </bag>
    </class>
</hibernate-mapping>

就他们自己而言,这两种方法都很好。例如,如果我只是使用Fluent映射,那么我的Foo表就会生成三个映射列。类似地,如果我只使用xml,那么NHibernate会创建一个带有ID和FooBarRelationship表的Foo表,其中包含ID,Foregin Keys和BarType列。不过这是问题所在:当我尝试同时使用xml和Fluent映射时,我得到NHibernateDuplicateMappingException 。另外,如果我只使用XML作为接口,但是使用Fluent作为子类,则完全忽略Fluent映射(即,它就像我只有xml一样)。

我已经做了很多搜索,但我找不到任何可能有用的信息。我可以对地图(甚至配置)做些什么来实现这个目的吗?

2 个答案:

答案 0 :(得分:0)

我认为您可能最终必须将整个Foo映射(和子类)放在XML文件中。我相信你是对的,你可以结合流畅的映射和hbm映射,但我不相信你可以在同一个实体时这样做,也许这也适用于子类?当通过与子类不同的方式定义根类(或接口)映射时,它似乎遇到了问题。

您可能想尝试为该接口执行尽可能多的映射,并使用流畅的子类,然后运行您的应用并将配置导出到hbm文件。

.Mappings(m =>
{
    m.FluentMappings.ExportTo(@"C:\")
}

从那里把它修剪成接口的映射和它的子类,然后添加你的多对多映射。我不打算假装它是一个干净的解决方案,但我不熟悉nHibernate映射的深层内部,以了解它如何合并来自hbm文件的映射与流畅或喋喋不休的映射之类的东西。

我不确定你还能尝试什么,除了切换到nHibernate的loquacious映射(我一直试图尝试它不是因为他们缺乏对多对多映射中where子句的支持)。

答案 1 :(得分:0)

我遇到了同样的问题,并提出了一个半优雅的解决方案。不能流畅地在.hbm.xml文件中映射相同的类。但是,您可以 单独映射一个子类。我的解决方案是创建一个抽象的FooBase类,该类可以流畅地映射并包含FluentNHibernate不支持的功能以外的所有内容。然后,创建一个继承FooBase的具体Foo类,并将该Foo类(仅不受支持的功能)映射到.hbm.xml文件中。

不利之处在于,它需要对您的域结构进行一些修改,但是IMO尝试导出和处理FluentNHibernate生成的XML会更优雅。