Wie ordnet man eine Aufzählung als int-Wert mit fließendem NHibernate zu?

88

Die Frage sagt wirklich alles, die Standardeinstellung ist, dass es als ein zugeordnet wird, stringaber ich brauche es, um es als zuzuordnen int.

Ich verwende derzeit PersistenceModelzum Festlegen meiner Konventionen, wenn dies einen Unterschied macht. Danke im Voraus.

Update Ich habe festgestellt, dass das Aufrufen der neuesten Version des Codes aus dem Trunk meine Probleme gelöst hat.

Garry Shutler
quelle
5
Wenn Sie das Problem selbst gelöst haben, sollten Sie es beantworten und als richtige Antwort markieren, damit zukünftige Suchende es finden.
Jeff Martin
Kannst du bitte die Antwort posten?
mxmissile
Fertig Jungs. Entschuldigung für die Verspätung. Ich war mir nicht sicher, was ich mit einer Frage anfangen sollte, die eher keine Frage war, da ich nur die neueste Version der Bibliotheken brauchte.
Garry Shutler
2
Essen für Google Bots: Ich habe "illegalen Zugriff auf das Laden von Sammlungen" erhalten, bevor ich dies für mein Enum-Mapping implementiert habe.
4imble

Antworten:

84

Die Art und Weise, diese Konvention zu definieren, hat sich vor einiger Zeit geändert.

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
quelle
4
Dies ist die richtige Antwort für die neueste Version von fließendem Winterschlaf
Sean Chambers
Stoßen. ^^ Was Sean gesagt hat.
Martin Suchanek
1
Dies scheint für alle Aufzählungstypen gut zu funktionieren, aber was ist, wenn Sie einige als Zeichenfolgen und einige als Ints möchten? Ich denke, dies sollte auf der Ebene der Eigenschaftszuordnung konfigurierbar sein.
UpTheCreek
4
Siehe die Antwort von @SztupY unten, die dies erweitert, um nullfähige Aufzählungen zu ermöglichen. stackoverflow.com/questions/439003/…
Jon Adams
45

Wie bereits erwähnt, brachte mich die neueste Version von Fluent NHibernate aus dem Kofferraum, wo ich sein musste. Eine Beispielzuordnung für eine Aufzählung mit dem neuesten Code lautet:

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

Der benutzerdefinierte Typ erzwingt, dass er als Instanz der Aufzählung behandelt wird, anstatt die zu verwenden GenericEnumMapper<TEnum>.

Ich denke tatsächlich darüber nach, einen Patch einzureichen, um zwischen einem Enum-Mapper, der eine Zeichenfolge beibehält, und einem, der ein Int beibehält, wechseln zu können, da dies etwas zu sein scheint, das Sie als Konvention festlegen sollten.


Dies tauchte in meiner letzten Aktivität auf und in den neueren Versionen von Fluent NHibernate haben sich die Dinge geändert, um dies zu vereinfachen.

Um alle Aufzählungen als Ganzzahlen zuzuordnen, können Sie jetzt eine Konvention wie folgt erstellen:

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

Dann muss Ihr Mapping nur noch sein:

Map(quote => quote.Status);

Sie fügen die Konvention wie folgt zu Ihrer Fluent NHibernate-Zuordnung hinzu.

Fluently.Configure(nHibConfig)
    .Mappings(mappingConfiguration =>
    {
        mappingConfiguration.FluentMappings
            .ConventionDiscovery.AddFromAssemblyOf<EnumConvention>();
    })
    ./* other configuration */
Garry Shutler
quelle
3
mit "int mode" als Standard. Wer hält Enums als Strings aufrecht?!
Andrew Bullock
4
Könnte eine Legacy-Datenbank mit bereits vorhandenen Zeichenfolgenwerten sein
Chris Haines
4
+1 hainesy. @ Andrew Bullock: Antwort auf Ihre Frage: Jeder, der sich mit realen Datenbanken befasst.
Sky Sanders
Gibt es eine IProperty-Schnittstelle in FN?
Tien Do
40

Vergessen Sie nicht nullbare Aufzählungen (wie ExampleEnum? ExampleProperty)! Sie müssen separat geprüft werden. So wird es mit der neuen Konfiguration im FNH-Stil gemacht:

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
quelle
4
+1 Für diesen Zusatz! Die erste Version funktioniert nicht für die nullbaren Aufzählungen (sie bleiben als Zeichenfolgen).
Longda
@SztupY Der Spaltentyp in der Datenbank ist int? Und wann akzeptiert der Typ Flags? Wie:MyEnum.Active | MyEnum.Paused
Ridermansb
@RidermandeSousaBarbosa: Für Flaggen überprüfen Sie hier: stackoverflow.com/questions/2805661/…
SztupY
25

So habe ich eine enum-Eigenschaft mit einem int-Wert zugeordnet:

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

funktioniert bei mir!

Felipe
quelle
2
Vielen Dank für die einfachste Antwort
Mike
Mein einziges Problem dabei ist, dass Sie daran denken müssen, es auf jede Aufzählung anzuwenden. Dafür wurden die Konventionen geschaffen.
Garry Shutler
Dies funktioniert beim Lesen, ist jedoch fehlgeschlagen, als ich eine Kriterienabfrage ausprobiert habe. Das Einrichten einer Konvention (siehe Antwort auf diese Frage) hat in allen Fällen funktioniert, die ich versucht habe.
Thomas Bratt
Nun, ich fand es großartig - aber das wird Probleme verursachen: siehe diesen Beitrag. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek
@UpTheCreek Es scheint, dass dies behoben wurde und jetzt von James Gregory vom NH-Team empfohlen wird: mail-archive.com/[email protected]/…
Ilya Kogan
1

Für Benutzer von Fluent NHibernate mit Automapping (und möglicherweise einem IoC-Container):

Das IUserTypeConventionist wie @ Julien ‚s Antwort oben: 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);
    }
}

Die Konfiguration von Fluent NHibernate Automapping kann folgendermaßen konfiguriert werden:

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

* Dann CreateSessionFactorykann das problemlos in einem IoC wie Castle Windsor (mit PersistenceFacility und Installer) verwendet werden. * *

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

Sie können ein NHibernate erstellen IUserTypeund es CustomTypeIs<T>()in der Eigenschaftskarte angeben .

James Gregory
quelle
0

Sie sollten die Werte als int / tinyint in Ihrer DB-Tabelle beibehalten. Um Ihre Aufzählung zuzuordnen, müssen Sie die Zuordnung korrekt angeben. Bitte sehen Sie unten Mapping und Enum-Beispiel,

Mapping-Klasse

öffentliche Klasse TransactionMap: ClassMap-Transaktion
{
    öffentliche TransactionMap ()
    {
        // Andere Zuordnungen
        ..... .....
        // Mapping für Enum
        Map (x => x.Status, "Status"). CustomType ();

        Tabelle ("Transaktion");
    }}
}}

Aufzählung

öffentliche Aufzählung TransactionStatus
{
   Warten = 1,
   Verarbeitet = 2,
   RolledBack = 3,
   Blockiert = 4,
   Rückerstattung = 5,
   Bereits verarbeitet = 6,
}}
Arkadas Kilic
quelle