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

Posted

技术标签:

【中文标题】使用 Fluent NHibernate 映射或模仿多对任意关系的选项?【英文标题】:Options for using mapping or mimicking a Many-To-Any Relationship with Fluent NHibernate? 【发布时间】:2013-04-19 16:56:01 【问题描述】:

编辑 - 快速总结

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

<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 文件中定义整个映射,而是只想映射&lt;many-to-any /&gt;。其余部分,我想保留在 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 的 Foo 表和一个 FooBarRelationship 表,其中包含 ID、Foregin Keys 和 BarType 列。不过,问题出在:当我尝试同时使用 xml 和 Fluent 映射时,我得到一个 NHibernateDuplicateMappingException。此外,如果我只使用 XML 作为接口,但使用 Fluent 作为子类,则完全忽略 Fluent 映射(即,它就像我只有 xml)。

我进行了大量搜索,但找不到任何可能有帮助的信息。我可以对地图(甚至配置)做些什么来让它工作吗?

【问题讨论】:

【参考方案1】:

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

您可能想尝试在 fluent 中为该接口及其子类进行尽可能多的映射,然后运行您的应用并将配置导出到 hbm 文件。

.Mappings(m =>

    m.FluentMappings.ExportTo(@"C:\")

从那里将其缩减为仅接口及其子类的映射,然后添加您的多对任意映射。我不会假装它是一个干净的解决方案,但我不熟悉 nHibernate 映射的深层内部结构,以了解它如何将来自 hbm 文件的映射与流畅或冗长的映射之类的东西合并。

我不确定你还能尝试什么,除了切换到 nHibernate 的 loquacious 映射(如果不是因为它们不支持多对多映射的 where 子句,我也很想尝试)。

【讨论】:

是的,我考虑过为整个层次结构导出 hbm,但我一直在努力避免它。如果可以的话,我会尝试切换到 NHibernate 的 loquacious 映射。也许我可以用复合类型做一些疯狂的事情。【参考方案2】:

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

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

【讨论】:

以上是关于使用 Fluent NHibernate 映射或模仿多对任意关系的选项?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Fluent NHibernate 映射泛型类

使用 2 种策略通过 fluent nhibernate 映射类层次结构

Fluent Nhibernate 映射多重连接

使用自动映射时如何使用 Fluent NHibernate Validator?

Fluent Nhibernate将集合映射到通用实体

Fluent NHibernate:如何将整个类映射为只读?