2009-09-27 27 views
30

estoy siguiendo el tutorial http://wiki.fluentnhibernate.org/Getting_started para crear mi primer proyecto NHibernate con Fluido NHibernateenumeración Mapeo con nhibernate fluidez

Tengo 2 tablas

1) Cuenta con campos

Id 
AccountHolderName 
AccountTypeId 

2) AccountType con campos

Id 
AccountTypeName 

Ahora mismo accou tipos nt pueden ser ahorros o corriente Así la tabla AccountTypes tiendas de 2 filas 1 - Ahorro 2 - actuales

Para la mesa AccoutType he definido enumeración

public enum AccountType { 
    Savings=1, 
    Current=2 
} 

Para tabla de cuentas que definen la clase de entidad

public class Account { 
    public virtual int Id {get; private set;} 
    public virtual string AccountHolderName {get; set;} 
    public virtual string AccountType {get; set;} 
} 

Las asignaciones de NHibernate fluidas son:

public AgencyMap() { 
    Id(o => o.Id); 
    Map(o => o.AccountHolderName); 
    Map(o => o.AccountType); 
} 

Cuando intento ejecutar la solución, se produce una excepción: InnerException = {"(XmlDocument) (2,4): error de validación XML: el elemento 'clase' en el espacio de nombres 'urna: nhibernate-mapping-2.2' tiene contenido incompleto Lista de posibles elementos esperados: 'meta, subselect, cache, sincronizar, comentar, tuplizer, id, composite-id' en el espacio de nombres 'ur ...

Supongo que es porque no he especificado ninguna asignación para AccountType.

Las preguntas son:

  1. ¿Cómo puedo usar AccountType enumeración lugar de una clase AccountType?
  2. Quizás estoy yendo en el camino equivocado. ¿Hay una mejor manera de hacer esto?

¡Gracias!

Respuesta

55

El siguiente parecer ya no funciona https://stackoverflow.com/a/503327/189412

¿Qué tal hacer esto:

public AgencyMap() { 
    Id(o => o.Id); 
    Map(o => o.AccountHolderName); 
    Map(o => o.AccountType).CustomType<AccountType>(); 
} 

El tipo personalizado se encarga de todo :)

+0

Aha! ¡Estaba usando CustomSqlType y no funcionaba! ¡Lo que necesitaba es CustomType! –

+8

AcountType es un Enum así que todas las entidades estarán sucias después de la carga. Ver http://stackoverflow.com/questions/3531937/enum-to-integer-mapping-causing-updates-on-every-flush – schoetbi

+0

+1 ¡Gracias m8 que funciona perfecto! – IamStalker

35
public class Account { 
    public virtual int Id {get; private set;} 
    public virtual string AccountHolderName {get; set;} 
    public virtual AccountType AccountType {get; set;} 
} 

public AgencyMap() { 
    Id(o => o.Id); 
    Map(o => o.AccountHolderName); 
    Map(o => o.AccountType); 
} 

Fluido NHibernate guarda los valores de enumeración como cadena por defecto si desea anular que es necesario suministrar una convención para ello. Algo como:

public class EnumConvention : 
    IPropertyConvention, 
    IPropertyConventionAcceptance 
{ 
    #region IPropertyConvention Members 

    public void Apply(IPropertyInstance instance) 
    { 
     instance.CustomType(instance.Property.PropertyType); 
    } 

    #endregion 

    #region IPropertyConventionAcceptance Members 

    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) 
    { 
     criteria.Expect(x => x.Property.PropertyType.IsEnum || 
     (x.Property.PropertyType.IsGenericType && 
     x.Property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) && 
     x.Property.PropertyType.GetGenericArguments()[0].IsEnum) 
     ); 
    } 

    #endregion 
} 

Casi olvidé que usted necesita agregar la convención a su configuración fluida también.Usted lo hace en el mismo lugar de agregar los mapeos:

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<BillingRecordMap>() 
.Conventions.AddFromAssemblyOf<EnumConvention>() 
+0

¡Perfecto! ¡Muchas gracias! – Puneet

+3

Consulte esta publicación/comentario sobre cómo extender esto para admitir enum nulos: http://stackoverflow.com/questions/439003/how-do-you-map-an-enum-as-an-int-value-with- fluent-nhibernate/2716236 # 2716236 –

+0

He actualizado el código con su sugerencia Mustafa. ¡Muchas gracias! – mhenrixon

1

Una excelente manera de hacerlo, es implementar la interfaz IUserType y Crear un CustomType con el reglas para escribir y leer, eso es un ejemplo para booleano:

public class CharToBoolean : IUserType 
{ 
    public SqlType[] SqlTypes => new[] { NHibernateUtil.String.SqlType }; 

    public Type ReturnedType => typeof(bool); 

    public bool IsMutable =>true; 

    public object Assemble(object cached, object owner) 
    { 
     return (cached); 
    } 

    public object DeepCopy(object value) 
    { 
     return (value); 
    } 

    public object Disassemble(object value) 
    { 
     return (value); 
    } 

    public new bool Equals(object x, object y) 
    { 
     if (ReferenceEquals(x, y)) return true; 

     var firstObject = x as string; 
     var secondObject = y as string; 

     if (string.IsNullOrEmpty(firstObject) || string.IsNullOrEmpty(secondObject)) return false; 

     if (firstObject == secondObject) return true; 
     return false; 
    } 

    public int GetHashCode(object x) 
    { 
     return ((x != null) ? x.GetHashCode() : 0); 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]); 

     if (obj == null) return null; 

     var value = (string)obj; 

     return value.ToBoolean(); 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     if(value != null) 
     { 
      if ((bool)value) 
      { 
       ((IDataParameter)cmd.Parameters[index]).Value = "S"; 
      } 
      else 
      { 
       ((IDataParameter)cmd.Parameters[index]).Value = "N"; 
      } 
     } 
     else 
     { 
      ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; 
     } 
    } 
    public object Replace(object original, object target, object owner) 
    { 
     return original; 
    } 
} 

}

el mapeo:

this.Map(x => x.DominioGenerico).Column("fldominiogen").CustomType<CharToBoolean>(); 

iT una muestra, pero se puede hacer esto con otros tipos.

Cuestiones relacionadas