在 nHibernate 中,我可以将抽象基类映射到集合吗?
我正在构建的 CMS 中有一个内容项的基类。它当前被标记为抽象,因为我只想实例化派生类。 BlogPost、Article、Photo 等派生类被设置为 nHibernate 中 ContentBase 类的连接子类。
我正在尝试在此类和 Tag 类之间建立多对多映射。我想要在 ContentBase 类上有一个标签集合,以及在标签类上有一个 ContentBase 项目集合。
nHibernate 是否允许我将抽象 ContentBase 类映射为 Tag 类上的集合?我假设不是,因为从数据库重新构建标签实体时它无法实例化此类的任何实例。我真的不想必须在 Tag 类上使用每种类型的内容项集合(例如 TaggedBlogPosts、TaggedArticles 等)。
我这样做的全部原因是因为从逻辑上讲,一个内容项可以有许多标签,并且 1 个标签可以属于多个内容项。为了让 nHibernate 在映射表中为我管理关系,我相信我必须设置一个多对多关联并将标签添加到 ContentBase.Tags 集合,然后将内容项添加到 Tags.TaggedContentItems 集合在 nHibernate 中创建映射表条目之前。
以下是我的映射供参考:
<class name="CMS.Core.Model.Tag,CMS.Core" table="bp_Tags">
<id column="TagName" name="TagName" type="String" unsaved-value="">
<generator class="assigned" />
</id>
<bag name="_taggedContentList" table="bp_Tags_Mappings" inverse="true" cascade="save-update" lazy="true">
<key column="TagName" />
<many-to-many class="CMS.Core.Model.ContentBase,CMS.Core" column="Target_Id" />
</bag>
</class>
<class name="CMS.Core.Model.ContentBase,CMS.Core" table="bp_Content">
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="SubmittedBy" column="SubmittedBy" type="string" length="256" not-null="true" />
<property name="SubmittedDate" column="SubmittedDate" type="datetime" not-null="true" />
<property name="PublishDate" column="PublishDate" type="datetime" not-null="true" />
<property name="State" column="State" type="CMS.Core.Model.ContentStates,CMS.Core" not-null="true" />
<property name="ContentType" column="ContentType" type="CMS.Core.Model.ContentTypes,CMS.Core" not-null="true" />
<bag name="_tagsList" table="bp_Tags_Mappings" lazy="false" cascade="save-update">
<key column="Target_Id" />
<many-to-many class="CMS.Core.Model.Tag,CMS.Core" column="TagName" lazy="false" />
</bag>
...
<joined-subclass name="CMS.Core.Model.BlogPost,CMS.Core" table="bp_Content_BlogPosts" >
<key column="Id" />
<property name="Body" type="string" column="Body" />
<property name="Title" type="string" column="Title" />
</joined-subclass>
...
I have a base class for content items in a CMS I'm building. It's currently marked abstract because I only want derived classes to be instantiated. Derived classes like BlogPost, Article, Photo, etc. are set up as a joined subclass to my ContentBase class in nHibernate.
I'm trying to set up a many-to-many mapping between this class and a Tag class. I want to have a collection of Tags on the ContentBase class, and a collection of ContentBase items on the tag class.
Will nHibernate allow me to map the abstract ContentBase class as a collection on the Tag class? I'm assuming not since it wouldn't be able to instantiate any instances of this class when reconstituting a Tag entity from the db. I really don't want to have to have to use a collection of content items per type (e.g. TaggedBlogPosts, TaggedArticles, etc.) on the Tag class.
The whole reason I'm doing this is because logically, a content item can have many tags, and 1 tag can belong to multiple content items. in order for nHibernate to manage the relationships for me in a mapping table, I believe I have to set up a many-to-many association and add the Tag to the ContentBase.Tags collection and then the content item to the Tags.TaggedContentItems collection before the mapping table entry is created in nHibernate.
Here are my mappings for reference:
<class name="CMS.Core.Model.Tag,CMS.Core" table="bp_Tags">
<id column="TagName" name="TagName" type="String" unsaved-value="">
<generator class="assigned" />
</id>
<bag name="_taggedContentList" table="bp_Tags_Mappings" inverse="true" cascade="save-update" lazy="true">
<key column="TagName" />
<many-to-many class="CMS.Core.Model.ContentBase,CMS.Core" column="Target_Id" />
</bag>
</class>
<class name="CMS.Core.Model.ContentBase,CMS.Core" table="bp_Content">
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="SubmittedBy" column="SubmittedBy" type="string" length="256" not-null="true" />
<property name="SubmittedDate" column="SubmittedDate" type="datetime" not-null="true" />
<property name="PublishDate" column="PublishDate" type="datetime" not-null="true" />
<property name="State" column="State" type="CMS.Core.Model.ContentStates,CMS.Core" not-null="true" />
<property name="ContentType" column="ContentType" type="CMS.Core.Model.ContentTypes,CMS.Core" not-null="true" />
<bag name="_tagsList" table="bp_Tags_Mappings" lazy="false" cascade="save-update">
<key column="Target_Id" />
<many-to-many class="CMS.Core.Model.Tag,CMS.Core" column="TagName" lazy="false" />
</bag>
...
<joined-subclass name="CMS.Core.Model.BlogPost,CMS.Core" table="bp_Content_BlogPosts" >
<key column="Id" />
<property name="Body" type="string" column="Body" />
<property name="Title" type="string" column="Title" />
</joined-subclass>
...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我还假设 Hibernate 需要实例化基类,这是有道理的,因为数据库中存在直接链接到它的数据。
看起来您的数据实体位于与主应用程序不同的程序集中。不实例化基类的目的是从业务角度来看,因此如果将构造函数设置为 Core 程序集的
内部
,是否可以实现您想要的效果?如果没有,问问自己可能会有所帮助:我在保护此功能免受谁的侵害?I would also assume that Hibernate would need to instantiate the base class, which makes sense, as there is data directly linked to it in the DB.
It looks like your data entities are in a separate assembly from your main application. The point of not instantiating the base is from a business point of view, so if you make the constructor
internal
to the Core assembly, does that accomplish what you want? If not, it may be helpful to ask yourself: who am I protecting this functionality from?NHibernate 应该允许您将抽象类映射为集合,只要您映射抽象类本身(看起来您已经这样做了)。
另一种方法是将策略更改为“每个类层次结构表”方法。这会将所有内容放入一个表中,并使用鉴别器列来定义内容类型。 NHibernate 知道如何根据鉴别器具体化每种内容类型。缺点是:
table-per-class-hierachy 是首选的默认映射策略(根据 NHibernate in Action)。我将从该方法开始,并在需要时将其修改为每个子类一个表。
一个完整的单独解决方案将保持映射不变,并依靠查询通过标签获取内容,而不必担心标签保留对内容集合的引用。
NHibernate should allow you to map the abstract class as a collection as long as you map the abstract class itself (it looks like you have).
An alternative is to change your strategy to the Table-per-class-hierachy approach. This puts all your content into a single table with a discriminator column to define the type of content. NHibernate knows how to materialize each content type based on the discriminator. The downside is that:
The table-per-class-hierachy is the preferred default mapping strategy (per NHibernate in Action). I would start with the approach and modify it to table-per-subclass when the need is certain.
A whole separate solution would be keep the mapping as is and rely on query to get the content by tag without worrying about the tags keeping a reference to a collection of content.