Bagaimana Anda memetakan enum sebagai nilai int dengan NHibernate yang lancar?


88

Pertanyaan mengatakan itu semua benar-benar, defaultnya adalah untuk memetakan sebagai stringtapi saya membutuhkannya untuk memetakan sebagai int.

Saat ini saya menggunakan PersistenceModeluntuk mengatur konvensi saya jika itu membuat perbedaan. Terima kasih sebelumnya.

Pembaruan Menemukan bahwa mendapatkan ke versi terbaru kode dari bagasi menyelesaikan kesengsaraan saya.


5
jika Anda sendiri yang memecahkan masalah, Anda harus menjawabnya, lalu menandainya sebagai jawaban yang benar sehingga calon pencari akan menemukannya.
Jeff Martin

Bisakah Anda memposting jawabannya?
mxmissile

Selesai guys. Maaf atas keterlambatannya. Saya tidak begitu yakin apa yang harus saya lakukan dengan pertanyaan yang lebih bersifat non-pertanyaan karena saya hanya membutuhkan versi terbaru dari perpustakaan.
Garry Shutler

2
Makanan untuk bot google: Saya mendapatkan "akses ilegal ke pemuatan koleksi" sebelum menerapkan ini untuk pemetaan enum saya.
4imble

Jawaban:


84

Cara untuk mendefinisikan konvensi ini kadang-kadang berubah, sekarang:

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
Ini adalah jawaban yang benar untuk versi terbaru dari fluent nhibernate
Sean Chambers

Menabrak. ^^ Apa yang Sean katakan.
Martin Suchanek

1
Sepertinya ini berfungsi dengan baik untuk semua jenis enum, tetapi bagaimana jika Anda menginginkan beberapa sebagai string dan beberapa sebagai int? Saya pikir ini harus dapat dikonfigurasi di tingkat pemetaan properti.
UpTheCreek

4
Lihat jawaban oleh @SztupY di bawah ini yang memperluas ini untuk memungkinkan enum nullable. stackoverflow.com/questions/439003/…
Jon Adams

45

Jadi, seperti yang disebutkan, mengeluarkan versi terbaru dari Fluent NHibernate dari bagasi membawa saya ke tempat yang saya inginkan. Contoh pemetaan enum dengan kode terbaru adalah:

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

Jenis kustom memaksanya untuk ditangani sebagai instance enum daripada menggunakan GenericEnumMapper<TEnum>.

Saya benar-benar mempertimbangkan untuk mengirimkan tambalan untuk dapat mengubah antara pemeta enum yang mempertahankan string dan yang mempertahankan int karena itu tampak seperti sesuatu yang harus Anda atur sebagai konvensi.


Ini muncul di aktivitas saya baru-baru ini dan banyak hal telah berubah di Fluent NHibernate versi terbaru untuk membuatnya lebih mudah.

Untuk membuat semua enum dipetakan sebagai integer, Anda sekarang dapat membuat konvensi seperti ini:

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

Maka pemetaan Anda hanya harus:

Map(quote => quote.Status);

Anda menambahkan konvensi ke pemetaan Fluent NHibernate seperti ini;

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

3
dengan "mode int" sebagai default. Siapa yang mempertahankan enum sebagai string ?!
Andrew Bullock

4
Mungkin database lama dengan nilai string sudah ada di sana
Chris Haines

4
+1 hainesy. @ Andrew Bullock: jawaban atas pertanyaan Anda: siapa saja yang berurusan dengan database dunia nyata.
Sky Sanders

Apakah ada antarmuka IProperty di FN?
Tien Do

40

Jangan lupa tentang enum nullable (like ExampleEnum? ExampleProperty)! Mereka perlu diperiksa secara terpisah. Beginilah cara melakukannya dengan konfigurasi gaya FNH baru:

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 Untuk tambahan ini! Versi pertama tidak berfungsi untuk enum nullable (mereka tetap sebagai string).
longda

@SztupY Jenis kolom dalam database adalah int? Dan kapan tipe accept Flags? Seperti:MyEnum.Active | MyEnum.Paused
ridermansb

@RidermandeSousaBarbosa: Untuk bendera, periksa di sini: stackoverflow.com/questions/2805661/…
SztupY

25

beginilah cara saya memetakan properti enum dengan nilai int:

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

bekerja untuk saya!


2
Terima kasih telah memberikan jawaban paling sederhana
Mike

Satu-satunya keraguan saya dengan ini adalah Anda harus ingat untuk menerapkannya ke setiap enum. Untuk itulah konvensi diciptakan.
Garry Shutler

Ini berfungsi untuk membaca tetapi gagal ketika saya mencoba kueri kriteria. Menyiapkan konvensi (lihat jawaban untuk pertanyaan ini) berhasil dalam semua kasus yang saya coba.
Thomas Bratt

Saya pikir itu bagus - tetapi ini akan menimbulkan masalah: lihat posting ini. nhforge.org/blogs/nhibernate/archive/2008/10/20/…
UpTheCreek

@UpTheCreek Tampaknya ini telah diperbaiki dan sekarang direkomendasikan oleh James Gregory dari tim NH: mail-archive.com/fluent-nhibernate@googlegroups.com/…
Ilya Kogan

1

Bagi mereka yang menggunakan Fluent NHibernate dengan Automapping (dan berpotensi wadah IoC):

Seperti jawaban IUserTypeConvention@ Julien di atas: 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);
    }
}

Konfigurasi Fluent NHibernate Automapping dapat dikonfigurasi seperti ini:

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

* Kemudian CreateSessionFactorydapat digunakan dalam IoC seperti Castle Windsor (menggunakan PersistenceFacility dan installer) dengan mudah. *

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

0

Anda dapat membuat NHibernate IUserType, dan menentukannya menggunakan CustomTypeIs<T>()di peta properti.


0

Anda harus menyimpan nilai sebagai int / tinyint di Tabel DB Anda. Untuk memetakan enum Anda, Anda perlu menentukan pemetaan dengan benar. Silakan lihat di bawah pemetaan dan sampel enum,

Kelas Pemetaan

kelas publik TransactionMap: ClassMap Transaction
{
    publik TransactionMap ()
    {
        // Pemetaan lainnya
        .....
        // Pemetaan untuk enum
        Peta (x => x.Status, "Status"). CustomType ();

        Tabel ("Transaksi");
    }
}

Enum

public enum TransactionStatus
{
   Menunggu = 1,
   Diproses = 2,
   RolledBack = 3,
   Diblokir = 4,
   Dikembalikan = 5,
   AlreadyProcessed = 6,
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.