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.

Garry Shutler
la source
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);
    }
}
Julien
la source
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 */
Garry Shutler
la source
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);
    }
}
SztupY
la source
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!

Felipe
la source
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/[email protected]/…
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() 
    );
lko
la source
0

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

James Gregory
la source
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,
}
Arkadas Kilic
la source