使用 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 文件中定义整个映射,而是只想映射<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 的 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 映射或模仿多对任意关系的选项?的主要内容,如果未能解决你的问题,请参考以下文章
使用 2 种策略通过 fluent nhibernate 映射类层次结构