Jak zmapować wyliczenie jako wartość int z płynnym NHibernate?

88

Pytanie mówi wszystko, tak naprawdę, domyślnie jest to mapowane jako, stringale potrzebuję, aby mapować jako int.

Obecnie używam PersistenceModeldo ustawiania moich konwencji, jeśli to ma znaczenie. Z góry dziękuję.

Aktualizacja Stwierdziliśmy, że uzyskanie najnowszej wersji kodu z bagażnika rozwiązało moje problemy.

Garry Shutler
źródło
5
jeśli sam rozwiązałeś problem, powinieneś na nie odpowiedzieć, a następnie oznaczyć jako poprawną odpowiedź, aby przyszli poszukiwacze mogli ją znaleźć.
Jeff Martin
Czy możesz opublikować odpowiedź?
mxmissile
Gotowe chłopaki. Przepraszam za opóźnienie. Nie byłem pewien, co mam zrobić z pytaniem, które nie było raczej pytaniem, ponieważ potrzebowałem tylko najnowszej wersji bibliotek.
Garry Shutler
2
Jedzenie dla robotów Google: otrzymywałem „nielegalny dostęp do pobierania kolekcji” przed zaimplementowaniem tego do mapowania wyliczeń.
4imble

Odpowiedzi:

84

Sposób definiowania tej konwencji zmieniał się czasami temu, teraz jest:

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
źródło
4
To jest poprawna odpowiedź dla najnowszej wersji Fluent nhibernate
Sean Chambers
Guz. ^^ Co powiedział Sean.
Martin Suchanek
1
Wygląda na to, że działa dobrze dla wszystkich typów wyliczeń, ale co, jeśli chcesz, aby niektóre były ciągami, a niektóre jako int? Myślę, że powinno to być konfigurowalne na poziomie mapowania właściwości.
UpTheCreek
4
Zobacz odpowiedź @SztupY poniżej, która rozszerza to, aby zezwolić na wyliczenia dopuszczające wartość null. stackoverflow.com/questions/439003/…
Jon Adams
45

Tak więc, jak wspomniano, pobranie najnowszej wersji Fluent NHibernate z bagażnika doprowadziło mnie do miejsca, w którym musiałem być. Przykładowe mapowanie wyliczenia z najnowszym kodem to:

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

Typ niestandardowy wymusza obsługę jako wystąpienie wyliczenia, a nie używanie GenericEnumMapper<TEnum>.

Właściwie rozważam przesłanie poprawki, aby móc zmieniać między maperem wyliczenia, który utrzymuje ciąg znaków, a takim, który utrzymuje int, ponieważ wydaje się, że jest to coś, co powinno być w stanie ustawić jako konwencję.


Pojawiło się to podczas mojej ostatniej aktywności i wiele się zmieniło w nowszych wersjach Fluent NHibernate, aby to ułatwić.

Aby zmapować wszystkie wyliczenia jako liczby całkowite, możesz teraz utworzyć taką konwencję:

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

Wtedy twoje mapowanie musi być tylko:

Map(quote => quote.Status);

Dodajesz konwencję do mapowania Fluent NHibernate w ten sposób;

Fluently.Configure(nHibConfig)
    .Mappings(mappingConfiguration =>
    {
        mappingConfiguration.FluentMappings
            .ConventionDiscovery.AddFromAssemblyOf<EnumConvention>();
    })
    ./* other configuration */
Garry Shutler
źródło
3
z domyślnym trybem „int”. Kto utrzymuje wyliczenia jako ciągi ?!
Andrew Bullock,
4
Może to być starsza baza danych, w której znajdują się już wartości łańcuchowe
Chris Haines,
4
+1 hainesy. @ Andrew Bullock: odpowiedź na twoje pytanie: każdy, kto ma do czynienia z prawdziwymi bazami danych.
Sky Sanders
Czy w FN jest interfejs IProperty?
Tien Do,
40

Nie zapomnij o wyliczeniach dopuszczających wartość zerową (jak ExampleEnum? ExampleProperty)! Należy je sprawdzić osobno. Oto, jak to się robi z nową konfiguracją stylu 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
źródło
4
+1 za ten dodatek! Pierwsza wersja nie działa w przypadku wyliczeń dopuszczających wartość null (pozostają one jako ciągi).
longda,
@SztupY Typ kolumny w bazie danych to int? A kiedy typ akceptuje Flagi? Na przykład:MyEnum.Active | MyEnum.Paused
ridermansb
@RidermandeSousaBarbosa: Flagi znajdziesz tutaj: stackoverflow.com/questions/2805661/…
SztupY
25

w ten sposób zamapowałem właściwość enum na wartość int:

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

pracuje dla mnie!

Felipe
źródło
2
Dziękuję za udzielenie najprostszej odpowiedzi
Mike,
Moją jedyną wadą jest to, że musisz pamiętać, aby zastosować go do każdego wyliczenia. Po to zostały stworzone konwencje.
Garry Shutler,
Działa to w przypadku czytania, ale nie powiodło się, gdy próbowałem zapytać kryteria. Utworzenie konwencji (zobacz odpowiedź na to pytanie) działało we wszystkich przypadkach, które próbowałem.
Thomas Bratt,
Cóż, myślałem, że było świetnie - ale to spowoduje problemy: zobacz ten post. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek
@UpTheCreek Wygląda na to, że zostało to naprawione i jest teraz zalecane przez Jamesa Gregory'ego z zespołu NH: mail-archive.com/[email protected]/…
Ilya Kogan
1

Dla osób używających Fluent NHibernate z Automappingiem (i potencjalnie kontenera IoC):

IUserTypeConventionJest @ Julien „s odpowiedź powyżej: 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);
    }
}

Konfigurację Fluent NHibernate Automapping można skonfigurować w następujący sposób:

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

* Następnie CreateSessionFactorymożna go łatwo wykorzystać w IoC, takim jak Castle Windsor (przy użyciu PersistenceFacility i instalatora). *

    Kernel.Register(
        Component.For<ISessionFactory>()
            .UsingFactoryMethod(() => CreateSessionFactory()),
            Component.For<ISession>()
            .UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
            .LifestylePerWebRequest() 
    );
lko
źródło
0

Możesz utworzyć NHibernate IUserTypei określić go CustomTypeIs<T>()na mapie właściwości.

James Gregory
źródło
0

Powinieneś zachować wartości jako int / tinyint w swojej tabeli DB. Aby zmapować wyliczenie, musisz poprawnie określić mapowanie. Zobacz poniżej mapowanie i przykład wyliczenia,

Klasa mapowania

public class TransactionMap: Transakcja ClassMap
{
    public TransactionMap ()
    {
        // Inne odwzorowania
        .....
        // Mapowanie dla wyliczenia
        Mapa (x => x.Status, "Stan"). CustomType ();

        Tabela („Transakcja”);
    }
}

Enum

publiczne wyliczenie TransactionStatus
{
   Waiting = 1,
   Przetworzono = 2,
   RolledBack = 3,
   Zablokowany = 4,
   Zwrócone = 5,
   AlreadyProcessed = 6,
}
Arkadas Kilic
źródło