2009-09-27 10 views
30

Je suivais le tutoriel http://wiki.fluentnhibernate.org/Getting_started pour créer mon premier projet NHibernate avec Fluent NHibernateMapping ENUM avec Fluent NHibernate

J'ai 2 tables

1) compte avec des champs

Id 
AccountHolderName 
AccountTypeId 

2) AccountType avec champs

Id 
AccountTypeName 

Maintenant types nt peuvent être épargne ou courant donc la table AccountTypes magasins 2 lignes 1 - épargne 2 - Courant

Pour table AccoutType Je définis ENUM

public enum AccountType { 
    Savings=1, 
    Current=2 
} 

Pour table de compte I définir la classe d'entité

public class Account { 
    public virtual int Id {get; private set;} 
    public virtual string AccountHolderName {get; set;} 
    public virtual string AccountType {get; set;} 
} 

Les applications de fluent NHibernate sont:

public AgencyMap() { 
    Id(o => o.Id); 
    Map(o => o.AccountHolderName); 
    Map(o => o.AccountType); 
} 

Lorsque j'essaie d'exécuter la solution, il donne une exception - InnerException = {"(XmlDocument) (2,4): Erreur de validation XML: L'élément 'class' dans l'espace de noms 'urn: nhibernate-mapping-2.2' a contenu incomplet. Liste des éléments possibles attendus: 'méta, sous-sélection, cache, synchroniser, commenter, tuplizer, id, composite-id' dans l'espace de nom ...

Je suppose que c'est parce que je n'ai pas spéci fi é de mapping pour AccountType.

Les questions sont les suivantes:

  1. Comment puis-je utiliser AccountType ENUM au lieu d'une classe AccountType?
  2. Peut-être que je me trompe. Y a-t-il une meilleure manière de faire cela?

Merci!

Répondre

55

Ce qui suit apparemment ne fonctionne plus https://stackoverflow.com/a/503327/189412

Que diriez-vous faire ceci:

public AgencyMap() { 
    Id(o => o.Id); 
    Map(o => o.AccountHolderName); 
    Map(o => o.AccountType).CustomType<AccountType>(); 
} 

Les poignées type personnalisé tout :)

+0

Aha! J'utilisais CustomSqlType et ça ne fonctionnait pas! Ce dont j'avais besoin était CustomType! –

+8

AcountType est un Enum donc toutes les entités seront sales après le chargement. Voir http://stackoverflow.com/questions/3531937/enum-to-integer-mapping-causing-updates-on-every-flush – schoetbi

+0

+1 Merci m8 qui fonctionne parfaitement! – IamStalker

35
public class Account { 
    public virtual int Id {get; private set;} 
    public virtual string AccountHolderName {get; set;} 
    public virtual AccountType AccountType {get; set;} 
} 

public AgencyMap() { 
    Id(o => o.Id); 
    Map(o => o.AccountHolderName); 
    Map(o => o.AccountType); 
} 

Courant NHibernate enregistre les valeurs enum comme chaîne par défaut si vous souhaitez remplacer que vous devez fournir une convention pour elle. Quelque chose comme:

public class EnumConvention : 
    IPropertyConvention, 
    IPropertyConventionAcceptance 
{ 
    #region IPropertyConvention Members 

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

    #endregion 

    #region IPropertyConventionAcceptance Members 

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

    #endregion 
} 

Presque oublié que vous deviez ajouter la convention à votre config couramment.Vous faites cela au même endroit que vous ajoutez les applications:

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<BillingRecordMap>() 
.Conventions.AddFromAssemblyOf<EnumConvention>() 
+0

Parfait! Merci beaucoup! – Puneet

+3

Voir ce post/commentaire sur la façon d'étendre cette prise en charge nullums enums: http://stackoverflow.com/questions/439003/how-do-you-map-an-enum-as-an-int-value-with- fluent-nhibernate/2716236 # 2716236 –

+0

J'ai mis à jour le code avec votre suggestion Mustafa. Merci beaucoup! – mhenrixon

1

Un excellent moyen de le faire, est de mettre en œuvre l'interface IUserType et de créer un CustomType avec le règles d'écriture et de lecture, un exemple thats booléen:

public class CharToBoolean : IUserType 
{ 
    public SqlType[] SqlTypes => new[] { NHibernateUtil.String.SqlType }; 

    public Type ReturnedType => typeof(bool); 

    public bool IsMutable =>true; 

    public object Assemble(object cached, object owner) 
    { 
     return (cached); 
    } 

    public object DeepCopy(object value) 
    { 
     return (value); 
    } 

    public object Disassemble(object value) 
    { 
     return (value); 
    } 

    public new bool Equals(object x, object y) 
    { 
     if (ReferenceEquals(x, y)) return true; 

     var firstObject = x as string; 
     var secondObject = y as string; 

     if (string.IsNullOrEmpty(firstObject) || string.IsNullOrEmpty(secondObject)) return false; 

     if (firstObject == secondObject) return true; 
     return false; 
    } 

    public int GetHashCode(object x) 
    { 
     return ((x != null) ? x.GetHashCode() : 0); 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]); 

     if (obj == null) return null; 

     var value = (string)obj; 

     return value.ToBoolean(); 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     if(value != null) 
     { 
      if ((bool)value) 
      { 
       ((IDataParameter)cmd.Parameters[index]).Value = "S"; 
      } 
      else 
      { 
       ((IDataParameter)cmd.Parameters[index]).Value = "N"; 
      } 
     } 
     else 
     { 
      ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; 
     } 
    } 
    public object Replace(object original, object target, object owner) 
    { 
     return original; 
    } 
} 

}

la mise en correspondance:

this.Map(x => x.DominioGenerico).Column("fldominiogen").CustomType<CharToBoolean>(); 

ESt un échantillon, mais vous pouvez le faire avec d'autres types.