Я пытаюсь создать отображение таблицы на иерархию с помощью NHibernate 2.0.1. У меня есть базовый класс со свойствами, которые существуют для каждого подкласса, которому наследовались другие классы. Все эти объекты сохраняются к одной таблице, названной сообщениями, которые содержат все возможные поля для каждого класса. Существует SourceID, который является различителем и должен указать, который Постепенно можно возвратиться для каждого подкласса. Вот мое текущее отображение.
<?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. Модель. BaseMessage, таким образом, я поместил значение различителя на этот класс также althout это, никогда не должен возвращать базовый класс. Это привело меня к некоторым antlr ошибкам.
Я проявляю неправильный подход к этой проблеме? Я хотел бы запросить таблицу и возвратить список другого POCOs, который все наследовали от базового класса. Это никогда не возвращало бы сам базовый класс.
ниже 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
}
}
Подход здравый. Я делал именно так несколько раз.
Вы могли бы сделать это явным в вашем коде, если бы конструктор по умолчанию BaseMessage был защищен.
Вам нужно объявить дискриминатор-значение и для базового класса.
Я предпочитаю строковые значения для дискриминаторов, так как это более понятно при выполнении SQL-запросов или отчетов. Кроме того, поскольку экземпляры BaseMessage не должны существовать, в качестве значения дискриминатора я бы использовал 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"; }
}
Наконец, ваш файл отображения слишком многословен, поскольку он включает значения, которые используются по умолчанию. Следующие атрибуты и элементы можно удалить:
Все ваши подклассы Message имеют свойство Body, поэтому переместите его в отображение базового класса. Если это поле может быть длиннее, чем varchar вашей базы данных, оно должно быть текстовым столбцом и иметь type="StringCLob", что соответствует string в .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>