NHibernate - 实体的映射标记

时间:2010-03-30 13:08:13

标签: nhibernate nhibernate-mapping

我一直在破坏我如何获取实体标签的想法 工作。我将直接进入一些数据库结构:

tblTag  
TagId - int32 - PK  
Name

tblTagEntity  
TagId - PK  
EntityId - PK  
EntityType - string - PK

tblImage  
ImageId - int32 - PK  

tblBlog  
BlogId - int32 - PK  

class Image  
Id  
EntityType { get { return "MyNamespace.Entities.Image"; }  
IList<Tag> Tags;

class Blog  
Id  
EntityType { get { return "MyNamespace.Entities.Blog"; }  
IList<Tag> Tags;

我在这里遇到的一个明显问题是EntityType是一个标识符,但是 在数据库中不存在。如果有人可以帮助解决这个问题 映射我会非常感激。

3 个答案:

答案 0 :(得分:0)

您可以在代码中将EntityType设为Enum。和/或,您可以尝试将EntityType作为数据库中的实际实体(tblEntityType)。

答案 1 :(得分:0)

您不需要实体类型。看一下any-type映射(它在关系表中将类型名称存储在数据库中,但在实体模型中不需要它。)

请参阅this blog post by ayende


编辑:试图写一个例子。

您可以为每个标记对象创建一个自己的表,这很简单直接,您甚至不需要任何类型:

<class name="Tag">
  <!-- ... -->
  <property name="Name"/>
</class>

<class name="Image">
  <!-- ... -->
  <bag name="Tags" table="Image_Tags">
    <key column="Image_FK"/>
    <many-to-many class="Tag" column="TagId "/>
  </bag>
</class>

尝试使用一些高级功能将其映射到一个表中,但我认为它不会这样:

<class name="Tag">
  <!-- ... -->
  <property name="Name"/>
  <bag name="Objects" table="tblTagEntity" access="noop">
    <key column="TagId"/>
    <many-to-any id-type="System.Int64" meta-type="System.String">

      <meta-value 
        value="IMAGE"
        class="Image"/>
      <meta-value 
        value="BLOG"
        class="Blog"/>

      <column name="EntityType"/>
      <column name="EntityId"/>
    </many-to-any>
  </bag>
</class>

<class name="Image">
  <!-- ... -->
  <bag name="Tags" table="tblTagEntity" where="EntityType='IMAGE'">
    <key column="EntityId"/>
    <many-to-many class="Tag" column="TagId "/>
  </bag>
</class>

这里的技巧是:

  • access="noop"指定外键,而实体模型中没有属性see this post
  • where="EntityType='IMAGE'"来过滤加载的数据。

问题是很可能EntityType没有设置为任何有用的值。这可以在某个地方修复,但我不认为这是值得的。

其他人可能有更好的主意。


编辑2:另一个(工作)解决方案

使关联表成为一个实体:

简而言之:

  • 标签=&gt; TagEntity:未映射或一对多反向(noop)
  • TagEntity =&gt;标签:多对一
  • TagEntity =&gt;对象:任何
  • 对象=&gt; TagEntity:一对多逆转

这应该是直接的。

类:

class Tag
{
  string Name { get; set; }
}

class TagEntity
{
  Tag Tag { get; set; }
  object Entity { get; set; }
}

class Image
{
  IList<TagEntity> tags { get; private set; }
}

唯一的缺点似乎是你必须确保双向关联是一致的而不加载大量数据。请注意,不存储反向集合。


编辑2:效果记录

当你添加/删除标签时,你可以做一个技巧。 TagEntity具有对标记实体的引用。实体还有一个TagEntities列表,但这被标记为反向。 (这意味着,它们已加载,但未存储。)

您可以在不加载所有标记的情况下添加和删除标记而无需加载实体。

添加:

  • 获取标记以添加(或加载代理,如果您拥有标记的ID)
  • 加载实体(只是代理,使用session.Load,此处没有数据库访问)
  • 创建新的TagEntity,分配标签和实体代理
  • 保存TagEntity

卸下:

  • 获取TagEntity以移除
  • 删除TagEntity。

在会话中,您没有为TagEntity分配/删除此标记。这很好,假设您只在此事务中添加或删除标记。

我在Tag上定义了TagEntities列表,您也可以这样做,而无需加载所有TagEntities来添加或删除TagEntities。

答案 2 :(得分:0)

让Stefans最终解决方案工作!这是我的最终映射:

图像

<bag name="TagEntites" table="tblTagEntity" cascade="all" fetch="join" inverse="true" where="EntityType='EntityImage'">
<key column="EntityId"></key>
<one-to-many class="TagEntity" />
</bag>

TagEntity

<id name="Id">
  <column name="TagEntityId"></column>
  <generator class="identity" />
</id>
<any name="Entity" id-type="System.Int32" meta-type="System.String">
  <meta-value value="EntityImage" class="Image" />
  <column name="EntityType"></column>
  <column name="EntityId"></column>
</any>
<many-to-one name="Tag" class="Tag" cascade="all" fetch="join">
  <column name="TagId"></column>
</many-to-one>