2009-03-17 10 views
26

Dado el siguiente escenario, quiero asignar la jerarquía de tipos al esquema de la base de datos utilizando Fluiber NHibernate.Asignación de herencia con NHibernate fluido

estoy usando NHibernate 2,0


Tipo Jerarquía

public abstract class Item 
{ 
    public virtual int ItemId { get; set; } 
    public virtual string ItemType { get; set; } 
    public virtual string FieldA { get; set; } 
} 

public abstract class SubItem : Item 
{ 
    public virtual string FieldB { get; set; } 
} 

public class ConcreteItemX : SubItem 
{ 
    public virtual string FieldC { get; set; } 
} 

public class ConcreteItemY : Item 
{ 
    public virtual string FieldD { get; set; } 
} 

See image

Los Item y SubItem clases son abstractas.


Base de datos de esquema

 
+----------+ +---------------+ +---------------+ 
| Item  | | ConcreteItemX | | ConcreteItemY | 
+==========+ +===============+ +===============+ 
| ItemId | | ItemId  | | ItemId  | 
| ItemType | | FieldC  | | FieldD  | 
| FieldA | +---------------+ +---------------+ 
| FieldB | 
+----------+ 

See image

El campo ItemType determina el tipo de hormigón.

Cada registro en la tabla ConcreteItemX tiene un registro único correspondiente en la tabla Item; del mismo modo para la tabla ConcreteItemY.

FieldB es siempre nulo si el tipo de elemento es ConcreteItemY.


El Mapping (hasta ahora)

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     WithTable("Item"); 
     Id(x => x.ItemId, "ItemId"); 
     Map(x => x.FieldA, "FieldA"); 

     JoinedSubClass<ConcreteItemX>("ItemId", MapConcreteItemX); 
     JoinedSubClass<ConcreteItemY>("ItemId", MapConcreteItemY); 
    } 

    private static void MapConcreteItemX(JoinedSubClassPart<ConcreteItemX> part) 
    { 
     part.WithTableName("ConcreteItemX"); 
     part.Map(x => x.FieldC, "FieldC"); 
    } 

    private static void MapConcreteItemY(JoinedSubClassPart<ConcreteItemY> part) 
    { 
     part.WithTableName("ConcreteItemX"); 
     part.Map(x => x.FieldD, "FieldD"); 
    } 
} 

FieldB no está asignada.


La pregunta

¿Cómo puedo asignar la propiedad de la clase FieldBSubItem usando Fluido NHibernate?

¿Hay alguna forma de que pueda aprovechar DiscriminateSubClassesOnColumn usando el campo ItemType?


Adición

soy capaz de lograr el resultado deseado mediante un archivo hbm.xml:

<class name="Item" table="Item"> 

    <id name="ItemId" type="Int32" column="ItemId"> 
    <generator class="native"/> 
    </id> 

    <discriminator column="ItemType" type="string"/> 

    <property name="FieldA" column="FieldA"/> 

    <subclass name="ConcreteItemX" discriminator-value="ConcreteItemX"> 
    <!-- Note the FieldB mapping here --> 
    <property name="FieldB" column="FieldB"/> 
    <join table="ConcreteItemX"> 
     <key column="ItemId"/> 
     <property name="FieldC" column="FieldC"/> 
    </join> 
    </subclass> 

    <subclass name="ConcreteItemY" discriminator-value="ConcreteItemY"> 
    <join table="ConcreteItemY"> 
     <key column="ItemId"/> 
     <property name="FieldD" column="FieldD"/> 
    </join> 
    </subclass> 

</class> 

¿Cómo llevar a cabo la asignación anterior utilizando Fluido NHibernate?

¿Es posible mezclar tabla por jerarquía de clases con tabla por subclase utilizando Fluidez NHibernate?

+0

¿Alguna razón por la cual esta marcada wiki de la comunidad? En cualquier caso, ¿podría aclarar la estrategia de mapeo que está utilizando? JoinedSubClassPart implica el patrón de tabla por subclase, pero decir que los elementos concretos persisten en la tabla de elementos implica el patrón de tabla por jerarquía de clases. –

+0

No estoy seguro de cómo cambiar la configuración wiki de la comunidad. Ignorando FieldB, puedo usar table-per-subclass. La presencia de FieldB me causa cierta confusión. Parece ser una mezcla de las dos estrategias. El tipo ConcreteItemX hereda FieldB de SubItem. FieldB persiste en la tabla de elementos. –

Respuesta

1

Bueno, no estoy seguro de que sea correcto, pero podría funcionar ... Si alguien puede hacer esto más limpiamente, me encantaría verlo (en serio, lo haría, este es un problema interesante) .

Usando las definiciones de clase exactas que diste, aquí están las asignaciones:

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     Id(x => x.ItemId); 
     Map(x => x.ItemType); 
     Map(x => x.FieldA); 

     AddPart(new ConcreteItemYMap()); 
    } 
} 

public class SubItemMap : ClassMap<SubItem> 
{ 
    public SubItemMap() 
    { 
     WithTable("Item"); 

     // Get the base map and "inherit" the mapping parts 
     ItemMap baseMap = new ItemMap(); 
     foreach (IMappingPart part in baseMap.Parts) 
     { 
      // Skip any sub class parts... yes this is ugly 
      // Side note to anyone reading this that might know: 
      // Can you use GetType().IsSubClassOf($GenericClass$) 
      // without actually specifying the generic argument such 
      // that it will return true for all subclasses, regardless 
      // of the generic type? 
      if (part.GetType().BaseType.Name == "JoinedSubClassPart`1") 
       continue; 
      AddPart(part); 
     } 
     Map(x => x.FieldB); 
     AddPart(new ConcreteItemXMap()); 
    } 
} 

public class ConcreteItemXMap : JoinedSubClassPart<ConcreteItemX> 
{ 
    public ConcreteItemXMap() 
     : base("ItemId") 
    { 
     WithTableName("ConcreteItemX"); 
     Map(x => x.FieldC); 
    } 
} 

public class ConcreteItemYMap : JoinedSubClassPart<ConcreteItemY> 
{ 
    public ConcreteItemYMap() 
     : base("ItemId") 
    { 
     WithTableName("ConcreteItemY"); 
     Map(x => x.FieldD); 
    } 
} 

Esas asignaciones de producir dos archivos hbm.xml como tal (algunos datos extraños retirados para mayor claridad):

<class name="Item" table="`Item`"> 
    <id name="ItemId" column="ItemId" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="FieldA" type="String"> 
     <column name="FieldA" /> 
    </property> 
    <property name="ItemType" type="String"> 
     <column name="ItemType" /> 
    </property> 
    <joined-subclass name="ConcreteItemY" table="ConcreteItemY"> 
     <key column="ItemId" /> 
     <property name="FieldD"> 
     <column name="FieldD" /> 
     </property> 
    </joined-subclass> 
    </class> 

    <class name="SubItem" table="Item"> 
    <id name="ItemId" column="ItemId" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="FieldB" type="String"> 
     <column name="FieldB" /> 
    </property> 
    <property name="ItemType" type="String"> 
     <column name="ItemType" /> 
    </property> 
    <property name="FieldA" type="String"> 
     <column name="FieldA" /> 
    </property> 
    <joined-subclass name="ConcreteItemX" table="ConcreteItemX"> 
     <key column="ItemId" /> 
     <property name="FieldC"> 
     <column name="FieldC" /> 
     </property> 
    </joined-subclass> 
    </class> 

Es feo, pero parece que podría generar un archivo de mapeo útil y ¡es Fluent! :/ Es posible que pueda modificar la idea un poco más para obtener exactamente lo que desea.

1

La línea de código: if (part.GetType().BaseType.Name == "JoinedSubClassPart1") puede reescribirse de la siguiente manera:

part.GetType().BaseType.IsGenericType && part.GetType().BaseType.GetGenericTypeDefinition() == typeof(JoinedSubClassPart<>) 
1

así es como he resuelto mi problema de herencia:

public static class DataObjectBaseExtension 
{ 
    public static void DefaultMap<T>(this ClassMap<T> DDL) where T : IUserAuditable 
    { 
     DDL.Map(p => p.AddedUser).Column("AddedUser"); 
     DDL.Map(p => p.UpdatedUser).Column("UpdatedUser"); 
    } 
} 

A continuación, puede añadir a su superclase mapa constructor :

internal class PatientMap : ClassMap<Patient> 
{ 
    public PatientMap() 
    { 
     Id(p => p.GUID).Column("GUID"); 
     Map(p => p.LocalIdentifier).Not.Nullable(); 
     Map(p => p.DateOfBirth).Not.Nullable(); 
     References(p => p.Sex).Column("RVSexGUID"); 
     References(p => p.Ethnicity).Column("RVEthnicityGUID"); 

     this.DefaultMap(); 
    } 


} 
+0

genial, gracias! – vondip

26

Sé que esto es muy viejo, pero yo Ahora es bastante simple configurar con fluidez para generar la asignación exacta que inicialmente deseaba. Como me encontré con esta publicación cuando buscaba la respuesta, pensé en publicarla.

Usted acaba de crear su ClassMap para la clase base sin ninguna referencia a sus subclases:

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     this.Table("Item"); 
     this.DiscriminateSubClassesOnColumn("ItemType"); 
     this.Id(x => x.ItemId, "ItemId"); 
     this.Map(x => x.FieldA, "FieldA"); 
    } 
} 

a continuación, asignar la subclase abstracta como esto:

public class SubItemMap: SubclassMap<SubItemMap> 
{ 
    public SubItemMap() 
    { 
     this.Map(x => x.FieldB); 
    } 
} 

a continuación, asignar sus subclases concretas de este modo:

public class ConcreteItemXMap : SubclassMap<ConcreteItemX> 
{ 
    public ConcretItemXMap() 
    { 
     this.Join("ConcreteItemX", x => 
     { 
      x.KeyColumn("ItemID"); 
      x.Map("FieldC") 
     }); 
    } 
} 

Espero que esto ayude a alguien más que busque este tipo de mapeo con fluidez.

+0

¡Agradable! Exactamente lo que necesitaba. – jweyrich

Cuestiones relacionadas