使用映射或模拟与 Fluent NHibernate 的多对任意关系的选项

本文关键字:任意 选项 关系 NHibernate Fluent 映射 模拟 | 更新日期: 2023-09-27 18:10:14

>编辑 - 快速摘要

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

  • <many-to-any />不受 Fluent NHibernate 支持
  • 想要在 XML 和 Fluent 之间拆分属性映射以映射<many-to-any />关系
  • 发现这可以通过命名查询实现
  • 当尝试同时使用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"都可能属于任意数量的其他表。由于这是一种"多对任意"的关系,因此Fluent仍然不支持它(是的,我知道NHibernate的代码映射支持这一点(。

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

我知道这可以通过命名查询和存储过程之类的东西来实现,但是使用此模式来定义我的关系时遇到了一些麻烦。

这是我的Foo类的流利映射,就像现在一样:

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 键和 BarType 列。但是,问题来了:当我尝试同时使用xml和Fluent映射时,我得到了一个NHibernateDuplicateMappingException。此外,如果我只使用XML作为接口,但使用Fluent作为子类,则Fluent映射将被完全忽略(即,它就像我只有xml一样(。

我已经做了相当多的搜索,但我无法找到任何可能有帮助的信息。我可以对地图(甚至配置(做些什么来使其工作吗?

使用映射或模拟与 Fluent NHibernate 的多对任意关系的选项

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

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

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

从那里将其修剪为接口及其子类的映射,然后添加多对任意映射。我不会假装这是一个干净的解决方案,但我不熟悉 nHibernate 映射的深层内容,以了解它如何合并来自 hbm 文件的映射,而不是流畅或可言的映射。

我不确定你还能尝试什么,除了切换到 nHibernate 的 loquacince 映射(如果不是因为他们缺乏对多对多映射上的 where 子句的支持,我也想尝试一下(。

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

缺点是它需要对域结构进行轻微修改,但IMO比尝试导出和操作FluentNHibernate生成的XML更优雅。