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.

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

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

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

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