2009-09-27 15 views
30

Mam następujący samouczek http://wiki.fluentnhibernate.org/Getting_started do tworzenia mojego pierwszego projektu NHibernate z Fluent NHibernatemapowania enum z Fluent NHibernate

Mam 2 tabele

1) Konto z pól

Id 
AccountHolderName 
AccountTypeId 

2) AccountType z polami

Id 
AccountTypeName 

Teraz aka Typy nt mogą być oszczędności lub Obecny więc tabela AccountTypes sklepów 2 rzędy 1 - Oszczędności 2 - Aktualne

Na stole AccoutType Mam zdefiniowane enum

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

Na stole Konta definiuję klasę encji

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

fluent NHibernate mapowania są:

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

Kiedy próbuję uruchomić rozwiązanie, daje wyjątek - InnerException = {"(XmlDocument) (2,4): Błąd sprawdzania poprawności XML: Element" klasa "w przestrzeni nazw" urn: nhibernate-mapping-2.2 "ma niepełna treść. Lista możliwych oczekiwanych elementów: 'meta, subselect, cache, synchronizacja, komentarz, tuplizer, id, composite-id' w przestrzeni nazw 'ur ...

Domyślam się, że to dlatego, że nie zdefiniowałem żadnego mapowania dla AccountType.

Pytania są:

  1. Jak mogę używać AccountType enum zamiast klasę AccountType?
  2. Może idę na niewłaściwym torze. Czy jest lepszy sposób to zrobić?

Dzięki!

Odpowiedz

55

Poniższa najwyraźniej nie działa https://stackoverflow.com/a/503327/189412

Jak o właśnie to robi:

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

niestandardowy typ obsługuje wszystko :)

+0

Aha! Używałem CustomSqlType i to nie działało! Potrzebowałem CustomType! –

+8

AcountType to Enum, więc wszystkie elementy będą zabrudzone po załadowaniu. Zobacz http://stackoverflow.com/questions/3531937/enum-to-integer-mapping-causing-updates-on-every-flush – schoetbi

+0

+1 Dzięki m8, który działa idealnie! – 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); 
} 

Fluent NHibernate zapisuje wartości enum jako ciąg domyślnie jeśli chcesz nadpisać, że trzeba dostarczyć konwencję dla niego. Coś takiego:

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 
} 

Prawie zapomniałem, że musisz dodać konwencję do swojej płynnej konfiguracji.Zrobisz to w tym samym miejscu dodać mapowania:

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

Idealnie! Dziękuję bardzo! – Puneet

+3

Zobacz ten post/komentarz, jak rozszerzyć ten, aby obsługiwać wyliczanie zerowe: http://stackoverflow.com/questions/439003/how-do-you-map-an-enum-as-an-int-value-with- fluent-nhibernate/2716236 # 2716236 –

+0

Zaktualizowałem kod z twoją sugestią Mustafa. Wielkie dzięki! – mhenrixon

1

Świetny sposób, aby to zrobić, to zaimplementuj interfejs IUserType i Create a CustomType z Zasady pisania i czytania, that's na przykład do wartości logicznej:

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

}

odwzorowanie:

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

its próbkę, ale można to zrobić z innych typów.

Powiązane problemy