NHibernate - отображение тегов объектов - PullRequest
1 голос
/ 30 марта 2010

Я ломал голову над тем, как заставить меня помечать сущности Работа. Я перейду прямо к структурированию базы данных:

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 голосов
/ 30 марта 2010

Вам не нужен тип объекта. Посмотрите на сопоставление любого типа (оно сохраняет имя типа в базе данных в таблице отношений, но оно не требуется в модели сущностей).

См. это сообщение в блоге 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" для указания внешнего ключа без свойства в модели объекта, см. Этот пост .
  • where="EntityType='IMAGE'" для фильтрации загруженных данных.

Проблема в том, что, скорее всего, для EntityType не установлено какое-либо полезное значение. Это может быть где-то исправлено, но я не думаю, что оно того стоит.

У кого-то еще есть идея получше.


Редактировать 2: другое (рабочее) решение

сделать таблицу ассоциаций сущностью:

короче:

  • Tag => TagEntity: не отображается или обратная связь один-ко-многим (noop)
  • TagEntity => Tag: многие-к-одному
  • TagEntity => Объект: любой
  • Object => 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, но он помечен как обратный. (Это означает, что они загружены, но не сохранены.)

Вы можете добавлять и удалять теги без загрузки сущности и без загрузки всех тегов.

Добавление:

  • Получить тег для добавления (или загрузить прокси, если у вас есть идентификатор тега)
  • Загрузить Entity (просто прокси, используя session.Load, здесь нет доступа к БД)
  • создание нового TagEntity, назначение тега и прокси-объекта лица
  • сохранить TagEntity

Удаление:

  • Получить TagEntity для удаления
  • удалить TagEntity.

В течение сеанса у вас нет этого тега, назначенного / удаленного из TagEntity. Это работает нормально, если вы только добавляете или удаляете теги в этой транзакции.

Если вы определите список TagEntities для Tag, вы можете сделать то же самое, не загружая все TagEntities, просто добавив или удалив один.

0 голосов
/ 30 марта 2010

Получил окончательное решение Стефана для работы! Вот мои последние отображения:

Изображение

<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>
0 голосов
/ 30 марта 2010

Вы можете сделать EntityType Enum в своем коде. И / или вы можете попытаться сделать EntityType реальной сущностью в вашей базе данных (tblEntityType).

...