2010-02-18 4 views
6

Я пытаюсь создать сопоставление таблицы за иерархию с помощью NHibernate 2.0.1. У меня есть базовый класс со свойствами, которые существуют для каждого подкласса, наследуемого другими классами. Все эти объекты сохраняются в одной таблице с именем «Сообщения», которая содержит все возможные поля для каждого класса. Существует SourceID, который является дискриминатором, и должен указывать, какой Poco должен возвращаться для каждого подкласса. Вот мое текущее сопоставление.Правильное сопоставление полиморфных отношений с NHibernate

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
        assembly="NS.Core" 
        namespace="NS.Core.Model"> 
    <class name="BaseMessage" table="Messages"> 
    <id name="MessageID" type="Int64"> 
     <column name="MessageID" /> 
     <generator class="native" /> 
    </id> 
    <discriminator column="SourceID" type="Int32"/> 
    <property name="DateCreated" access="property" column="DateCreated" type="DateTime" not-null="true"/> 
    <property name="DatePublished" access="property" column="DatePublished" type="DateTime"/> 
    <property name="SourceID" access="property" column="SourceID" type="Int32"/> 
    <many-to-one name="User" column="UserID" access="property" cascade="none" lazy="false" fetch="join" outer-join="true" /> 
    <subclass name="NMessage" discriminator-value="0"> 
     <property name="Body" access="property" column="Body" type="String"/> 
    </subclass> 
    <subclass name="BMessage" discriminator-value="1"> 
     <property name="Title" access="property" column="Title" type="String"/> 
     <property name="Body" access="property" column="Body" type="String"/> 
    </subclass> 
    <subclass name="CMessage" discriminator-value="2"> 
     <property name="Url" access="property" column="Url" type="String"/> 
     <property name="Body" access="property" column="Body" type="String"/> 
    </subclass> 
    </class> 
</hibernate-mapping> 

я получаю запрашивание ошибке: Не удалось отформатировать значение дискриминатора в SQL строку объекта NS.Core.Model.BaseMessage поэтому я ставлю значение дискриминатора на этом классе слишком althout он никогда не должен возвращать базовый класс. Это привело меня к некоторым ошибкам antlr.

Я принимаю неправильный подход к этой проблеме? Я хотел бы запросить таблицу и вернуть список разных POCO, которые все наследуют от базового класса. Он никогда не вернет базовый класс.

ниже является BaseMessage.cs

using System; 
using System.Collections.Generic; 
using System.Runtime.Serialization; 
using System.Text; 

namespace NS.Core.Model 
{ 

    [Serializable] 
    [DataContract] 
    [KnownType(typeof(User))] 
    public class BaseMessage 
    { 
     #region Private variables 
     private long _messageID; 
     private DateTime? _dateCreated; 
     private DateTime? _datePublished; 
     private int _sourceID; 
     private User _user = new User(); 

     #endregion 

     #region Properties 
     [DataMember] 
     public virtual long MessageID 
     { 
      get { return _messageID; } 
      set { this._messageID = value; } 
     } 
      [DataMember] 
     public virtual DateTime? DateCreated 
     { 
      get { return _dateCreated; } 
      set { this._dateCreated = value; } 
     } 
     [DataMember] 
     public virtual DateTime? DatePublished 
     { 
      get { return _datePublished; } 
      set { this._datePublished = value; } 
     } 
     [DataMember] 
     public virtual int SourceID 
     { 
      get { return _sourceID; } 
      set { this._sourceID = value; } 
     } 
     [DataMember] 
     public virtual User User 
     { 
      get 
      { 
       if (this._user != null) 
       { return this._user; } 
       else { return new User(); } 
      } 
      set { this._user = value; } 
     } 
     #endregion 
    } 
} 
+0

Вы можете разместить код BaseMessage? – hackerhasid

+0

обновлен.Надеюсь, что это поможет – CountCet

ответ

9

Подход звук. Я сделал это несколько раз.

Вы можете сделать это явным в своем коде, чтобы мой конструктор по умолчанию BaseMessage был защищен.

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

Я предпочитаю строковые значения для дискриминаторов, как это яснее при выполнении SQL-запросов или отчетов. Кроме того, поскольку экземпляры BaseMessage shoudl не существуют, in будет использовать null для своего значения дискриминатора.

<class name="BaseMessage" table="Messages" discriminator-value="null"> 
    <id /> 
    <discriminator column="SourceID" /> 
    <subclass name="NMessage" discriminator-value="NMessage"> 
    </subclass> 
    <subclass name="BMessage" discriminator-value="BMessage"> 
    </subclass> 
    <subclass name="CMessage" discriminator-value="CMessage"> 
    </subclass> 
</class> 

Кроме того, я вижу, что вы сопоставили свойство столбцу дискриминатора. Вместо этого вы должны иметь метод, который возвращает что-то уникальное для класса - в этом случае код.

Обратите внимание, что вы не можете изменить класс сопоставленного объекта после его сохранения. Даже не меняя дискриминатора. Если вы изменили его с помощью SQL, ваш кеш второго уровня все равно будет содержать версию с исходным классом.

class BaseMessage 
{ 
    public virtual string MessageType { return null; } 
} 

class NMessage : BaseMessage 
{ 
    public override string MessageType { return "NMessage"; } 
} 

Наконец, ваш файл сопоставления является чрезмерно подробным, так как он содержит значения, которые являются значениями по умолчанию. Следующие атрибуты и элементы могут быть удалены:

  • доступа = «свойство» - это по умолчанию
  • тип = «String» - все типы, которые вы используете могут быть выведены из вашего класса .NET
  • столбец = «COL» - по умолчанию совпадает с именем
  • аналогичны для столбца ID элемента

Всего ваших подклассов Message имеет свойство тела, поэтому перемещать его к отображению базового класса. Если это поле может быть больше, чем ваш VARCHAR базы данных, он должен быть текстовый столбец и иметь тип = «StringCLob», который отображает в строку в .NET

<class name="BaseMessage" table="Messages" discriminator-value="null"> 
    <id name="MessageID"> 
     <generator class="native" /> 
    </id> 
    <discriminator column="SourceID"/> 
    <property name="DateCreated" /> 
    <property name="DatePublished" /> 
    <many-to-one name="User" column="UserID" cascade="none" lazy="false" fetch="join" outer-join="true" /> 
    <property name="Body" type="StringCLob" /> 
    <subclass name="NMessage" discriminator-value="NMessage"> 
    </subclass> 
    <subclass name="BMessage" discriminator-value="BMessage"> 
     <property name="Title" /> 
    </subclass> 
    <subclass name="CMessage" discriminator-value="CMessage"> 
     <property name="Url" /> 
    </subclass> 
</class> 
+0

Что делать, если база данных не содержит исходный код для BaseMessage, который никогда не хранится в базе данных? – CountCet

+0

В качестве отображаемого класса требуется значение дискриминатора. То, что такое значение никогда не будет существовать, является логикой проверки уровня приложения. –

+0

Это был краткий пример, и тело не в каждом примере, но ваш ответ заставил его работать. Благодаря! – CountCet

Смежные вопросы