2010-02-18 15 views
6

Intento crear una asignación de tabla por jerarquía utilizando NHibernate 2.0.1. Tengo una clase base con propiedades que existen para cada subclase de la que heredan otras clases. Todos estos objetos se conservan en una tabla llamada Mensajes que contienen todos los campos posibles para cada clase. Hay un SourceID que discrimina y debe indicar qué Poco devolver para cada subclase. Aquí está mi mapeo actual.Correlación correcta de una relación polimórfica con 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> 

me sale un error diciendo consulta No se puede dar formato a un valor de discriminador cadena SQL de la entidad NS.Core.Model.BaseMessage por lo que poner un valor discriminador de esta clase también althout nunca debe devolver la clase base. Eso me llevó a algunos errores antlr.

¿Estoy tomando el enfoque equivocado para este problema? Me gustaría consultar la tabla y obtener una lista de POCO diferentes que todos heredan de la clase base. Nunca devolvería la clase base en sí misma.

a continuación es la 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

se puede enviar el código de mensaje base? – hackerhasid

+0

actualizado.Espero que ayude – CountCet

Respuesta

9

El enfoque es el sonido. He hecho exactamente esto varias veces.

Podrías hacerlo explícito en tu código al tener el constructor predeterminado de BaseMessage protegido.

También debe declarar un valor discriminador en la clase base.

Favorezco los valores de cadena para los discriminadores, ya que esto es más claro al realizar consultas o informes SQL. Además, dado que las instancias de BaseMessage shoudl no existen, in usaría null para su valor discriminador.

<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> 

Además, veo que ha asignado una propiedad a la columna del discriminador. En su lugar, debe tener un método que devuelva algo único para la clase, en este caso, el código.

Tenga en cuenta que no puede cambiar la clase de una entidad asignada después de que se haya guardado. Ni siquiera cambiando el discriminador. Si lo cambió a través de SQL, su caché de segundo nivel todavía tendrá una versión con la clase original.

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

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

Finalmente, su archivo de asignación es demasiado detallado ya que incluye valores que son los predeterminados. Los siguientes atributos y elementos pueden ser removidos:

  • acceso = "propiedad" - este es el valor predeterminado
  • type = "string" - todos los tipos que utiliza se puede deducir de su clase de .NET
  • columna = "COL" - por defecto es el mismo que el nombre
  • de manera similar para el elemento de la columna ID

Todos sus subclases Mensaje tener la propiedad del cuerpo, por lo que se mueve hacia el mapeo de clase base. Si este campo puede ser más largo que su base de datos varchar, debe ser una columna de texto y tienen type = "StringCLob" que se localiza en cadena en .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

¿Qué ocurre si la base de datos no contiene un SourceID para BaseMessage, que nunca se almacena en la base de datos? – CountCet

+0

Como una clase mapeada, requiere un valor discriminador. Que tal valor nunca existirá es la lógica de validación de nivel de aplicación. –

+0

Este fue un ejemplo sucinto y el cuerpo no está en todos los ejemplos, pero tu respuesta hizo que esto funcionara. ¡Gracias! – CountCet

Cuestiones relacionadas