¿Cómo se asigna una enumeración como un valor int con fluidez NHibernate?

88

La pregunta lo dice todo realmente, el valor predeterminado es que se asigne como un mapa, stringpero necesito que se asigne como int.

Actualmente estoy usando PersistenceModelpara establecer mis convenciones si eso hace alguna diferencia. Gracias por adelantado.

Actualización Descubrí que obtener la última versión del código desde el maletero resolvió mis problemas.

Garry Shutler
fuente
5
Si resolvió el problema usted mismo, debe responderlo y luego marcarlo como la respuesta correcta para que los futuros usuarios lo encuentren.
Jeff Martin
¿Puedes publicar la respuesta?
mxmissile
Hecho chicos. Perdón por el retraso. No estaba realmente seguro de qué se suponía que debía hacer con una pregunta que no era una pregunta, ya que solo necesitaba la última versión de las bibliotecas.
Garry Shutler
2
Comida para los bots de Google: estaba obteniendo "acceso ilegal a la colección de carga" antes de implementar esto para mi mapeo de enumeración.
4imble

Respuestas:

84

La forma de definir esta convención cambió a veces, ahora es:

public class EnumConvention : IUserTypeConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.PropertyType.IsEnum);
    }

    public void Apply(IPropertyInstance target)
    {
        target.CustomType(target.Property.PropertyType);
    }
}
Julien
fuente
4
Esta es la respuesta correcta para la versión más reciente de nhibernate fluido
Sean Chambers
Bache. ^^ Lo que dijo Sean.
Martin Suchanek
1
Parece que funciona bien para todos los tipos de enumeración, pero ¿qué pasa si quieres algunas como cadenas y otras como ints? Creo que esto debería ser configurable a nivel de mapeo de propiedades.
UpTheCreek
4
Vea la respuesta de @SztupY a continuación que amplía esto para permitir enumeraciones que aceptan valores NULL. stackoverflow.com/questions/439003/…
Jon Adams
45

Entonces, como se mencionó, obtener la última versión de Fluent NHibernate del maletero me llevó a donde tenía que estar. Un ejemplo de mapeo para una enumeración con el último código es:

Map(quote => quote.Status).CustomTypeIs(typeof(QuoteStatus));

El tipo personalizado obliga a que se maneje como una instancia de la enumeración en lugar de usar GenericEnumMapper<TEnum>.

De hecho, estoy considerando enviar un parche para poder cambiar entre un mapeador de enumeración que persiste una cadena y uno que persiste un int, ya que parece algo que debería poder establecer como una convención.


Esto apareció en mi actividad reciente y las cosas han cambiado en las versiones más nuevas de Fluent NHibernate para facilitar esto.

Para hacer que todas las enumeraciones se mapeen como números enteros, ahora puede crear una convención como esta:

public class EnumConvention : IUserTypeConvention
{
    public bool Accept(IProperty target)
    {
        return target.PropertyType.IsEnum;
    }

    public void Apply(IProperty target)
    {
        target.CustomTypeIs(target.PropertyType);
    }

    public bool Accept(Type type)
    {
        return type.IsEnum;
    }
}

Entonces tu mapeo solo tiene que ser:

Map(quote => quote.Status);

Agrega la convención a su mapeo Fluent NHibernate así;

Fluently.Configure(nHibConfig)
    .Mappings(mappingConfiguration =>
    {
        mappingConfiguration.FluentMappings
            .ConventionDiscovery.AddFromAssemblyOf<EnumConvention>();
    })
    ./* other configuration */
Garry Shutler
fuente
3
con "int mode" como predeterminado. ¿Quién persiste en las enumeraciones como cadenas?
Andrew Bullock
4
Podría ser una base de datos heredada con valores de cadena que ya están allí
Chris Haines
4
+1 hainesy. @ Andrew Bullock: responda a su pregunta: cualquiera que se ocupe de bases de datos del mundo real.
Sky Sanders
¿Existe alguna interfaz IProperty en FN?
Tien Do
40

¡No te olvides de las enumeraciones que aceptan valores NULL (como ExampleEnum? ExampleProperty)! Deben comprobarse por separado. Así es como se hace con la nueva configuración de estilo FNH:

public class EnumConvention : IUserTypeConvention
{
    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)
            );
    }

    public void Apply(IPropertyInstance target)
    {
        target.CustomType(target.Property.PropertyType);
    }
}
SztupY
fuente
4
+1 ¡Por esta adición! La primera versión no funciona para las enumeraciones que aceptan valores NULL (permanecen como cadenas).
Longda
@SztupY ¿El tipo de columna en la base de datos es int? ¿Y cuando el tipo acepta Banderas? Me gusta:MyEnum.Active | MyEnum.Paused
ridermansb
@RidermandeSousaBarbosa: para ver las banderas aquí: stackoverflow.com/questions/2805661/…
SztupY
25

así es como he mapeado una propiedad enum con un valor int:

Map(x => x.Status).CustomType(typeof(Int32));

¡funciona para mi!

Felipe
fuente
2
Gracias por proporcionar la respuesta más simple
Mike
Mi único reparo con esto es que debes recordar aplicarlo a cada enumeración. Para eso se crearon las convenciones.
Garry Shutler
Esto funciona para leer, pero falló cuando intenté una consulta de criterios. Sin embargo, la configuración de una convención (consulte la respuesta a esta pregunta) funcionó en todos los casos que intenté.
Thomas Bratt
Bueno, pensé que era genial, pero esto causará problemas: vea esta publicación. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek
@UpTheCreek Parece que esto se ha solucionado y ahora es recomendado por James Gregory del equipo de NH: mail-archive.com/[email protected]/…
Ilya Kogan
1

Para aquellos que usan Fluent NHibernate con Automapping (y potencialmente un contenedor de IoC):

El IUserTypeConventiones tan @ Julien respuesta 's arriba: https://stackoverflow.com/a/1706462/878612

public class EnumConvention : IUserTypeConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Property.PropertyType.IsEnum);
    }

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

La configuración de Fluent NHibernate Automapping podría configurarse así:

    protected virtual ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
            .Database(SetupDatabase)
            .Mappings(mappingConfiguration =>
                {
                    mappingConfiguration.AutoMappings
                        .Add(CreateAutomappings);
                }
            ).BuildSessionFactory();
    }

    protected virtual IPersistenceConfigurer SetupDatabase()
    {
        return MsSqlConfiguration.MsSql2008.UseOuterJoin()
        .ConnectionString(x => 
             x.FromConnectionStringWithKey("AppDatabase")) // In Web.config
        .ShowSql();
    }

    protected static AutoPersistenceModel CreateAutomappings()
    {
        return AutoMap.AssemblyOf<ClassInAnAssemblyToBeMapped>(
            new EntityAutomapConfiguration())
            .Conventions.Setup(c =>
                {
                    // Other IUserTypeConvention classes here
                    c.Add<EnumConvention>();
                });
    }

* Luego, CreateSessionFactoryse puede utilizar en un IoC como Castle Windsor (usando un PersistenceFacility y un instalador) fácilmente. *

    Kernel.Register(
        Component.For<ISessionFactory>()
            .UsingFactoryMethod(() => CreateSessionFactory()),
            Component.For<ISession>()
            .UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
            .LifestylePerWebRequest() 
    );
lko
fuente
0

Puede crear un NHibernate IUserTypey especificarlo usando CustomTypeIs<T>()en el mapa de propiedades.

James Gregory
fuente
0

Debe mantener los valores como int / tinyint en su tabla de base de datos. Para mapear su enumeración, debe especificar el mapeo correctamente. Consulte la siguiente muestra de mapeo y enumeración,

Clase de mapeo

TransactionMap de clase pública: Transacción de ClassMap
{
    TransactionMap público ()
    {
        // Otras asignaciones
        .....
        // Mapeo de enumeración
        Mapa (x => x.Status, "Estado"). CustomType ();

        Tabla ("Transacción");
    }
}

Enum

Public enum TransactionStatus
{
   Esperando = 1,
   Procesado = 2,
   RolledBack = 3,
   Bloqueado = 4,
   Reembolsado = 5,
   AlreadyProcessed = 6,
}
Arkadas Kilic
fuente