Comment mappez-vous une énumération en tant que valeur int avec NHibernate fluent?


88

La question dit tout vraiment, la valeur par défaut est de mapper en tant que stringmais j'en ai besoin pour mapper en tant que int.

J'utilise actuellement PersistenceModelpour définir mes conventions si cela fait une différence. Merci d'avance.

Mise à jour J'ai trouvé que l'accès à la dernière version du code à partir du coffre a résolu mes problèmes.


5
si vous avez résolu le problème vous-même, vous devez y répondre, puis marquez-le comme la bonne réponse afin que les futurs chercheurs la trouvent.
Jeff Martin

Pouvez-vous s'il vous plaît poster la réponse?
mxmissile

Terminé les gars. Désolé pour le retard. Je n'étais pas vraiment sûr de ce que j'étais censé faire avec une question qui était plus une non-question car j'avais juste besoin de la dernière version des bibliothèques.
Garry Shutler le

2
Nourriture pour les robots google: J'obtenais un "accès illégal au chargement de la collection" avant de l'implémenter pour mon enum mapping.
4imble

Réponses:


84

La façon de définir cette convention a parfois changé il y a, c'est maintenant:

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
C'est la bonne réponse pour la version la plus récente de fluent nhibernate
Sean Chambers

Bosse. ^^ Ce que Sean a dit.
Martin Suchanek

1
Cela semble fonctionner correctement pour tous les types d'énumérations, mais que faire si vous en voulez sous forme de chaînes et d'autres sous forme d'entiers? Je pense que cela devrait être configurable au niveau du mappage de propriété.
UpTheCreek

4
Voir la réponse de @SztupY ci-dessous qui étend cela pour permettre des énumérations nullables. stackoverflow.com/questions/439003/…
Jon Adams

45

Donc, comme mentionné, obtenir la dernière version de Fluent NHibernate du coffre m'a amené là où je devais être. Un exemple de mappage pour une énumération avec le dernier code est:

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

Le type personnalisé l'oblige à être traité comme une instance de l'énumération plutôt que d'utiliser le GenericEnumMapper<TEnum>.

J'envisage en fait de soumettre un correctif pour pouvoir changer entre un mappeur enum qui persiste une chaîne et un qui persiste un int, car cela semble être quelque chose que vous devriez pouvoir définir comme convention.


Cela est apparu sur mon activité récente et les choses ont changé dans les nouvelles versions de Fluent NHibernate pour rendre cela plus facile.

Pour que toutes les énumérations soient mappées sous forme d'entiers, vous pouvez maintenant créer une convention comme celle-ci:

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

Ensuite, votre cartographie doit seulement être:

Map(quote => quote.Status);

Vous ajoutez la convention à votre mappage Fluent NHibernate comme ceci;

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

3
avec "mode int" par défaut. Qui persiste les énumérations sous forme de chaînes?!
Andrew Bullock

4
Peut-être une base de données héritée avec des valeurs de chaîne déjà présentes
Chris Haines

4
+1 foin. @ Andrew Bullock: répondez à votre question: quiconque traite des bases de données du monde réel.
Sky Sanders

Existe-t-il une interface IProperty dans FN?
Tien Do

40

N'oubliez pas les énumérations nullables (comme ExampleEnum? ExampleProperty)! Ils doivent être vérifiés séparément. Voici comment procéder avec la nouvelle configuration de style 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 Pour cet ajout! La première version ne fonctionne pas pour les énumérations nullables (elles restent sous forme de chaînes).
longda

@SztupY Le type de colonne dans la base de données est int? Et quand le type accepte les drapeaux? Comme:MyEnum.Active | MyEnum.Paused
ridermansb

@RidermandeSousaBarbosa: Pour les drapeaux, vérifiez ici: stackoverflow.com/questions/2805661/…
SztupY

25

voici comment j'ai mappé une propriété enum avec une valeur int:

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

travaille pour moi!


2
Merci d'avoir fourni la réponse la plus simple
Mike

Mon seul reproche est que vous devez vous rappeler de l'appliquer à chaque énumération. C'est pour cela que les conventions ont été créées.
Garry Shutler

Cela fonctionne pour la lecture mais a échoué lorsque j'ai essayé une requête de critères. La mise en place d'une convention (voir la réponse à cette question) a fonctionné dans tous les cas que j'ai essayés.
Thomas Bratt

Eh bien, je pensais que c'était génial - mais cela posera des problèmes: voir ce post. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek

@UpTheCreek Il semble que cela a été corrigé et est maintenant recommandé par James Gregory de l'équipe NH: mail-archive.com/fluent-nhibernate@googlegroups.com/…
Ilya Kogan

1

Pour ceux qui utilisent Fluent NHibernate avec Automapping (et potentiellement un conteneur IoC):

C'est IUserTypeConventioncomme la réponse de @ Julien ci-dessus: 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 configuration de Fluent NHibernate Automapping peut être configurée comme ceci:

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

* Ensuite, le CreateSessionFactorypeut être utilisé dans un IoC tel que Castle Windsor (en utilisant une PersistenceFacility et un installateur) facilement. *

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

0

Vous pouvez créer un NHibernate IUserTypeet le spécifier en utilisant CustomTypeIs<T>()sur la carte des propriétés.


0

Vous devez conserver les valeurs int / tinyint dans votre table DB. Pour mapper votre énumération, vous devez spécifier le mappage correctement. Veuillez voir ci-dessous le mappage et l'exemple d'énumération,

Classe de cartographie

public class TransactionMap: ClassMap Transaction
{
    TransactionMap publique ()
    {
        // Autres mappages
        .....
        // Mappage pour enum
        Map (x => x.Status, "Statut"). CustomType ();

        Table ("Transaction");
    }
}

Enum

public enum TransactionStatus
{
   En attente = 1,
   Traité = 2,
   RolledBack = 3,
   Bloqué = 4,
   Remboursé = 5,
   Déjà traité = 6,
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.