Come si mappa un'enumerazione come valore int con NHibernate fluente?


88

La domanda dice tutto davvero, l'impostazione predefinita è che venga mappato come a stringma ho bisogno che venga mappato come file int.

Attualmente sto usando PersistenceModelper impostare le mie convenzioni se questo fa la differenza. Grazie in anticipo.

Aggiorna Ho scoperto che accedere all'ultima versione del codice dal trunk ha risolto i miei guai.


5
se hai risolto il problema da solo, dovresti rispondere, quindi contrassegnarlo come risposta corretta in modo che i futuri ricercatori lo trovino.
Jeff Martin

Puoi per favore pubblicare la risposta?
mxmissile

Fatto ragazzi. Scusa per il ritardo. Non ero veramente sicuro di cosa avrei dovuto fare con una domanda che fosse più di una non domanda poiché avevo solo bisogno dell'ultima versione delle librerie.
Garry Shutler

2
Cibo per i bot di Google: stavo ottenendo "l'accesso illegale al caricamento della raccolta" prima di implementarlo per la mia mappatura enum.
4imble

Risposte:


84

Il modo per definire questa convenzione è cambiato a volte fa, ora è:

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);
    }
}

4
Questa è la risposta corretta per la versione più recente di fluente nhibernate
Sean Chambers

Bump. ^^ Cosa ha detto Sean.
Martin Suchanek

1
Sembra che funzioni bene per tutti i tipi di enumerazione, ma cosa succede se vuoi alcuni come stringhe e altri come int? Penso che questo dovrebbe essere configurabile a livello di mappatura delle proprietà.
UpTheCreek

4
Vedere la risposta di @SztupY di seguito che estende questo per consentire enumerazioni nullable. stackoverflow.com/questions/439003/…
Jon Adams

45

Quindi, come accennato, ottenere l'ultima versione di Fluent NHibernate dal bagagliaio mi ha portato dove dovevo essere. Un esempio di mappatura per un'enumerazione con il codice più recente è:

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

Il tipo personalizzato impone che venga gestito come un'istanza dell'enumerazione anziché utilizzare il GenericEnumMapper<TEnum>.

In realtà sto considerando di inviare una patch per poter cambiare tra un mappatore enum che persiste una stringa e uno che persiste un int in quanto sembra qualcosa che dovresti essere in grado di impostare come convenzione.


Questo è saltato fuori dalla mia attività recente e le cose sono cambiate nelle versioni più recenti di Fluent NHibernate per renderlo più facile.

Per fare in modo che tutte le enumerazioni siano mappate come numeri interi, ora puoi creare una convenzione in questo modo:

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

Quindi la tua mappatura deve essere solo:

Map(quote => quote.Status);

Aggiungi la convenzione alla tua mappatura Fluent NHibernate in questo modo;

Fluently.Configure(nHibConfig)
    .Mappings(mappingConfiguration =>
    {
        mappingConfiguration.FluentMappings
            .ConventionDiscovery.AddFromAssemblyOf<EnumConvention>();
    })
    ./* other configuration */

3
con "modalità int" come impostazione predefinita. Chi persiste enumerazioni come stringhe ?!
Andrew Bullock,

4
Potrebbe essere un database legacy con valori stringa già presenti
Chris Haines

4
+1 hainesy. @ Andrew Bullock: rispondi alla tua domanda: chiunque si occupi di database del mondo reale.
Sky Sanders

Esiste un'interfaccia IProperty in FN?
Tien Do

40

Non dimenticare le enumerazioni nullable (come ExampleEnum? ExampleProperty)! Devono essere controllati separatamente. Ecco come si fa con la nuova configurazione in stile 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);
    }
}

4
+1 per questa aggiunta! La prima versione non funziona per le enumerazioni nullable (rimangono come stringhe).
longda

@SztupY Il tipo di colonna nel database è int? E quando il tipo accetta Bandiere? Come:MyEnum.Active | MyEnum.Paused
ridermansb

@RidermandeSousaBarbosa: Per controllare le bandiere qui: stackoverflow.com/questions/2805661/...
SztupY

25

ecco come ho mappato una proprietà enum con un valore int:

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

per me va bene!


2
Grazie per aver fornito la risposta più semplice
Mike

Il mio unico scrupolo con questo è che devi ricordarti di applicarlo a ogni enum. È per questo che sono state create le convenzioni.
Garry Shutler

Funziona per la lettura ma non è riuscito quando ho provato una query di criteri. La creazione di una convenzione (vedere la risposta a questa domanda) ha funzionato in tutti i casi che ho provato.
Thomas Bratt,

Beh, ho pensato che fosse fantastico, ma questo causerà problemi: guarda questo post. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek

@UpTheCreek Sembra che questo sia stato risolto ed è ora consigliato da James Gregory del team NH: mail-archive.com/fluent-nhibernate@googlegroups.com/…
Ilya Kogan

1

Per coloro che utilizzano Fluent NHibernate con Automapping (e potenzialmente un contenitore IoC):

L' IUserTypeConventionè come @ Julien 's risposta di cui sopra: 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 configurazione Fluent NHibernate Automapping potrebbe essere configurata in questo modo:

    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>();
                });
    }

* Quindi CreateSessionFactorypuò essere utilizzato in un IoC come Castle Windsor (utilizzando PersistenceFacility e programma di installazione) facilmente. *

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

0

È possibile creare un NHibernate IUserTypee specificarlo utilizzando CustomTypeIs<T>()sulla mappa delle proprietà.


0

Dovresti mantenere i valori come int / tinyint nella tua tabella DB. Per mappare la tua enumerazione devi specificare la mappatura correttamente. Vedere di seguito la mappatura e l'esempio di enum,

Classe di mappatura

public class TransactionMap: ClassMap Transaction
{
    public TransactionMap ()
    {
        // Altre mappature
        .....
        // Mappatura per enum
        Mappa (x => x.Status, "Status"). CustomType ();

        Tabella ("Transazione");
    }
}

Enum

public enum TransactionStatus
{
   In attesa = 1,
   Elaborato = 2,
   RolledBack = 3,
   Bloccato = 4,
   Rimborsato = 5,
   Già elaborato = 6,
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.