Presisi dan skala desimal dalam EF Code First

230

Saya bereksperimen dengan pendekatan kode-pertama ini, tapi saya sekarang tahu bahwa properti tipe System.Decimal akan dipetakan ke kolom sql tipe desimal (18, 0).

Bagaimana cara mengatur ketepatan kolom database?

Dave Van den Eynde
sumber
11
salah satu caranya adalah dengan menggunakan [Column(TypeName = "decimal(18,4)")]atribut untuk properti desimal Anda
S.Serpooshan
[Kolom (TypeName = "desimal (18,4)")] bekerja dengan luar biasa !!!
Brian Rice

Jawaban:

257

Jawaban dari Dave Van den Eynde sudah ketinggalan zaman. Ada 2 perubahan penting, dari EF 4.1 dan seterusnya kelas ModelBuilder sekarang DbModelBuilder dan sekarang ada DecimalPropertyConfiguration.HasPrecision Method yang memiliki tanda tangan:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

di mana presisi adalah jumlah total digit yang akan disimpan db, terlepas dari di mana titik desimal jatuh dan skala adalah jumlah tempat desimal yang akan disimpannya.

Oleh karena itu tidak perlu untuk beralih melalui properti seperti yang ditunjukkan tetapi hanya dapat dipanggil dari

public class EFDbContext : DbContext
{
   protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
   {
       modelBuilder.Entity<Class>().Property(object => object.property).HasPrecision(12, 10);

       base.OnModelCreating(modelBuilder);
   }
}
AlexC
sumber
Bagi siapa pun yang mendapatkan masalah dengan DbModelBuilder, cobalahSystem.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
Lloyd Powell
1
Saya perhatikan Anda tidak pernah menelepon base.OnModelCreating(modelBuilder);. Apakah itu disengaja atau hanya menjadi korban pengetikan kode online alih-alih dalam IDE?
BenSwayne
1
@BenSwayne terima kasih atas tempatnya, ini adalah kelalaian saya, bukan sesuatu yang disengaja. Saya akan mengedit jawabannya.
AlexC
26
2 argumen untuk HasPrecision (presisi, skala) kurang didokumentasikan. presisi adalah jumlah total digit yang akan disimpan, di mana pun titik desimal berada. skala adalah jumlah tempat desimal yang akan disimpannya.
Chris Moschini
1
Apakah ada konfigurasi EF untuk mengaturnya untuk semua properti desimal pada semua entitas di satu tempat? Kami biasanya menggunakan (19,4). Alangkah baiknya jika ini diterapkan secara otomatis ke semua properti desimal, jadi kita tidak bisa lupa untuk mengatur presisi properti dan kehilangan presisi yang diantisipasi dalam perhitungan.
Mike de Klerk
89

Jika Anda ingin mengatur presisi untuk semua decimalsdi EF6, Anda dapat mengganti DecimalPropertyConventionkonvensi default yang digunakan di DbModelBuilder:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
    modelBuilder.Conventions.Add(new DecimalPropertyConvention(38, 18));
}

Default DecimalPropertyConventiondi EF6 memetakan decimalproperti ke decimal(18,2)kolom.

Jika Anda hanya ingin masing-masing properti memiliki presisi yang ditentukan, maka Anda dapat mengatur presisi untuk properti entitas pada DbModelBuilder:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>().Property(e => e.Value).HasPrecision(38, 18);
}

Atau, tambahkan EntityTypeConfiguration<>entitas untuk yang menentukan presisi:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new MyEntityConfiguration());
}

internal class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
    internal MyEntityConfiguration()
    {
        this.Property(e => e.Value).HasPrecision(38, 18);
    }
}
kjbartel
sumber
1
Solusi favorit saya Berfungsi sempurna saat menggunakan CodeFirst dan migrasi: EF mencari semua properti di semua kelas tempat "desimal" digunakan dan menghasilkan migrasi untuk properti ini. Bagus!
okieh
75

Saya bersenang-senang membuat Atribut Khusus untuk ini:

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class DecimalPrecisionAttribute : Attribute
{
    public DecimalPrecisionAttribute(byte precision, byte scale)
    {
        Precision = precision;
        Scale = scale;

    }

    public byte Precision { get; set; }
    public byte Scale { get; set; }

}

menggunakannya seperti ini

[DecimalPrecision(20,10)]
public Nullable<decimal> DeliveryPrice { get; set; }

dan keajaiban terjadi pada pembuatan model dengan beberapa refleksi

protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
    foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAttribute)).GetTypes()
                                   where t.IsClass && t.Namespace == "YOURMODELNAMESPACE"
                                   select t)
     {
         foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<DecimalPrecisionAttribute>() != null).Select(
                p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) }))
         {

             var entityConfig = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(classType).Invoke(modelBuilder, null);
             ParameterExpression param = ParameterExpression.Parameter(classType, "c");
             Expression property = Expression.Property(param, propAttr.prop.Name);
             LambdaExpression lambdaExpression = Expression.Lambda(property, true,
                                                                      new ParameterExpression[]
                                                                          {param});
             DecimalPropertyConfiguration decimalConfig;
             if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
             {
                 MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[7];
                 decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
             }
             else
             {
                 MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[6];
                 decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
             }

             decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
        }
    }
}

bagian pertama adalah untuk mendapatkan semua kelas dalam model (atribut khusus saya didefinisikan dalam perakitan itu jadi saya menggunakannya untuk mendapatkan perakitan dengan model)

foreach kedua mendapatkan semua properti di kelas itu dengan atribut khusus, dan atribut itu sendiri sehingga saya bisa mendapatkan data presisi dan skala

setelah itu saya harus menelpon

modelBuilder.Entity<MODEL_CLASS>().Property(c=> c.PROPERTY_NAME).HasPrecision(PRECISION,SCALE);

jadi saya memanggil modelBuilder.Entity () dengan refleksi dan menyimpannya dalam variabel entityConfig kemudian saya membangun ekspresi lambda "c => c.PROPERTY_NAME"

Setelah itu, jika desimalnya dapat dibatalkan saya panggil

Property(Expression<Func<TStructuralType, decimal?>> propertyExpression) 

metode (saya menyebutnya dengan posisi dalam array, itu tidak ideal saya tahu, bantuan apa pun akan sangat dihargai)

dan jika itu tidak dapat dibatalkan saya sebut

Property(Expression<Func<TStructuralType, decimal>> propertyExpression)

metode.

Memiliki DecimalPropertyConfiguration saya memanggil metode HasPrecision.

KinSlayerUY
sumber
3
Terima kasih untuk ini. Itu menyelamatkan saya dari menghasilkan ribuan ekspresi lambda.
Sean
1
Ini berfungsi dengan baik, dan sangat bersih! Untuk EF 5, saya mengubah System.Data.Entity.ModelConfiguration.ModelBuilder ke System.Data.Entity.DbModelBuilder
Colin
3
saya gunakan MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });untuk mendapatkan kelebihan yang benar. tampaknya bekerja sejauh ini.
fscan
3
Saya telah membungkus ini menjadi perpustakaan dan membuatnya lebih mudah untuk menelepon dari DbContext: github.com/richardlawley/EntityFrameworkAttributeConfig (juga tersedia melalui nuget)
Richard
Richard, saya suka ide proyek Anda, tetapi adakah yang membutuhkan EF6? Saya akan menggunakannya jika ada versi yang kompatibel dengan EF5, sehingga saya dapat menggunakannya dengan versi ODP.NET saya.
Patrick Szalapski
50

Dengan menggunakan DecimalPrecisonAttributedari KinSlayerUY, di EF6 Anda dapat membuat konvensi yang akan menangani masing-masing properti yang memiliki atribut (yang bertentangan dengan pengaturan DecimalPropertyConventionseperti pada jawaban ini yang akan memengaruhi semua properti desimal).

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class DecimalPrecisionAttribute : Attribute
{
    public DecimalPrecisionAttribute(byte precision, byte scale)
    {
        Precision = precision;
        Scale = scale;
    }
    public byte Precision { get; set; }
    public byte Scale { get; set; }
}

public class DecimalPrecisionAttributeConvention
    : PrimitivePropertyAttributeConfigurationConvention<DecimalPrecisionAttribute>
{
    public override void Apply(ConventionPrimitivePropertyConfiguration configuration, DecimalPrecisionAttribute attribute)
    {
        if (attribute.Precision < 1 || attribute.Precision > 38)
        {
            throw new InvalidOperationException("Precision must be between 1 and 38.");
        }

        if (attribute.Scale > attribute.Precision)
        {
            throw new InvalidOperationException("Scale must be between 0 and the Precision value.");
        }

        configuration.HasPrecision(attribute.Precision, attribute.Scale);
    }
}

Kemudian di Anda DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}
kjbartel
sumber
@MichaelEdenfield Sebenarnya tidak ada di EF6. Karenanya mengapa saya menambahkan dua jawaban, yang ini dan yang lainnya yang Anda sebutkan. Ini adalah atribut yang bisa Anda tempatkan pada properti desimal tunggal daripada memengaruhi semua properti desimal dalam model.
kjbartel
Sayang saya, tidak melihat Anda menulis keduanya: \
Michael Edenfield
1
Jika Anda akan memeriksa batas Precision, maka saya sarankan mengatur batas atas ke 28 (jadi > 28dalam kondisi Anda). Menurut dokumentasi MSDN, System.Decimalhanya dapat mewakili maksimum 28-29 digit presisi ( msdn.microsoft.com/en-us/library/364x0z75.aspx ). Atribut juga menyatakan Scalesebagai byte, yang berarti prasyarat Anda attribute.Scale < 0tidak perlu.
NathanAldenSr
2
@ kjbartel Memang benar bahwa beberapa penyedia database mendukung tindakan yang lebih besar dari 28; Namun, menurut MSDN, System.Decimaltidak. Oleh karena itu tidak masuk akal untuk menetapkan prasyarat batas atas untuk sesuatu yang lebih besar dari 28; System.Decimaltampaknya tidak dapat mewakili angka sebesar itu. Perlu diketahui juga bahwa atribut ini berguna untuk penyedia data selain SQL Server. Misalnya, numerictipe PostgreSQL mendukung hingga 131072 digit presisi.
NathanAldenSr
1
@NathanAldenSr Seperti yang saya katakan, basis data menggunakan desimal titik tetap ( msdn ) sedangkan System.Decimal adalah titik mengambang . Mereka sangat berbeda. Misalnya memiliki decimal(38,9)kolom akan senang menahan System.Decimal.MaxValuetetapi decimal(28,9)kolom tidak akan. Tidak ada alasan untuk membatasi presisi hanya 28.
kjbartel
47

Rupanya, Anda dapat mengganti metode DbContext.OnModelCreating () dan mengkonfigurasi presisi seperti ini:

protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().Property(product => product.Price).Precision = 10;
    modelBuilder.Entity<Product>().Property(product => product.Price).Scale = 2;
}

Tapi ini kode yang cukup membosankan ketika Anda harus melakukannya dengan semua properti Anda yang berkaitan dengan harga, jadi saya datang dengan ini:

    protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        var properties = new[]
        {
            modelBuilder.Entity<Product>().Property(product => product.Price),
            modelBuilder.Entity<Order>().Property(order => order.OrderTotal),
            modelBuilder.Entity<OrderDetail>().Property(detail => detail.Total),
            modelBuilder.Entity<Option>().Property(option => option.Price)
        };

        properties.ToList().ForEach(property =>
        {
            property.Precision = 10;
            property.Scale = 2;
        });

        base.OnModelCreating(modelBuilder);
    }

Adalah praktik yang baik bahwa Anda memanggil metode dasar ketika Anda menimpa metode, meskipun implementasi basis tidak melakukan apa pun.

Pembaruan: Artikel ini juga sangat membantu.

Dave Van den Eynde
sumber
10
Terima kasih, ini mengarahkan saya ke arah yang benar. Dalam CTP5 sintaks telah berubah untuk memungkinkan penambahan Presisi dan Skala dalam pernyataan yang sama: modelBuilder.Entity <Product> () .Property (product => product.Price) .HasPrecision (6, 2);
Kol
2
Namun, bukankah menyenangkan memiliki semacam "default" yang dapat Anda tetapkan untuk semua desimal?
Dave Van den Eynde
3
Saya pikir tidak base.OnModelCreating(modelBuilder);perlu menelepon . Dari metadata DbContext dalam VS: The default implementation of this method does nothing, but it can be overridden in a derived class such that the model can be further configured before it is locked down.
Matt Jenkins
@ Matt: Itu bagus, tetapi sebagai implementor saya tidak harus peduli tentang ini dan selalu memanggil pangkalan.
Dave Van den Eynde
@ Dave dan @Matt: Ada komentar "PENTING" untuk memanggil pangkalan. Ini adalah praktik yang baik, tetapi ketika sumber EF memiliki implementasi kosong, itu menyesatkan untuk mengklaim itu Penting. Itu membuat orang bertanya-tanya apa yang dilakukan pangkalan. Saya sangat ingin tahu apa yang PENTING saya dekompilasi ke ef5.0 untuk memeriksa. Tidak ada apa-apa di sana. Jadi hanya kebiasaan baik.
phil soady
30

Entity Framework Ver 6 (Alpha, rc1) memiliki sesuatu yang disebut Konvensi Kustom . Untuk mengatur presisi desimal:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<decimal>().Configure(config => config.HasPrecision(18, 4));
}

Referensi:

mxasim
sumber
22
[Column(TypeName = "decimal(18,2)")]

ini akan bekerja dengan migrasi pertama kode EF Core seperti dijelaskan di sini .

Elnoor
sumber
1
Jika Anda hanya menambahkan ini ke model Anda, Anda bisa mendapatkanThe store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
Savage
@Savage sepertinya masalah dengan penyedia database Anda atau versi database
Elnoor
@Enn Savage sudah benar, ini akan menyebabkan kesalahan dalam EF Migrations 6.x. Versi lawas, non-Core tidak mendukung spesifikasi presisi / skala melalui atribut Kolom, dan tidak melakukan apa pun (default ke 18,2) jika Anda menggunakan atribut DataType. Untuk membuatnya berfungsi melalui Atribut di EF 6.x, Anda perlu menerapkan ekstensi Anda sendiri ke ModelBuilder.
Chris Moschini
1
@ChrisMoschini, saya mengubah jawaban saya menyebutkan EF Core. Terima kasih
Elnoor
14

baris kode ini bisa menjadi cara yang lebih sederhana untuk melakukan hal yang sama:

 public class ProductConfiguration : EntityTypeConfiguration<Product>
    {
        public ProductConfiguration()
        {
            this.Property(m => m.Price).HasPrecision(10, 2);
        }
    }
armadillo.mx
sumber
9

- UNTUK EF CORE - dengan menggunakan System.ComponentModel.DataAnnotations;

gunakan [Column( TypeName = "decimal( presisi , skala )")]

Presisi = Total jumlah karakter yang digunakan

Skala = Jumlah total setelah titik. (mudah bingung)

Contoh :

public class Blog
{
    public int BlogId { get; set; }
    [Column(TypeName = "varchar(200)")]
    public string Url { get; set; }
    [Column(TypeName = "decimal(5, 2)")]
    public decimal Rating { get; set; }
}

Lebih detail di sini: https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-types

sofsntp
sumber
3

Di EF6

modelBuilder.Properties()
    .Where(x => x.GetCustomAttributes(false).OfType<DecimalPrecisionAttribute>().Any())
    .Configure(c => {
        var attr = (DecimalPrecisionAttribute)c.ClrPropertyInfo.GetCustomAttributes(typeof (DecimalPrecisionAttribute), true).FirstOrDefault();

        c.HasPrecision(attr.Precision, attr.Scale);
    });
pengguna3332875
sumber
Jawaban ini tampaknya merupakan peningkatan ke jawaban lain yang mendefinisikan atribut, Anda harus mengeditnya menjadi jawaban itu
Rhys Bevilaqua
3

Anda selalu dapat memberi tahu EF untuk melakukan ini dengan konvensi di kelas Konteks di fungsi OnModelCreating sebagai berikut:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // <... other configurations ...>
    // modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    // modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    // modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

    // Configure Decimal to always have a precision of 18 and a scale of 4
    modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
    modelBuilder.Conventions.Add(new DecimalPropertyConvention(18, 4));

    base.OnModelCreating(modelBuilder);
}

Ini hanya berlaku untuk Kode F EF Pertama dan berlaku untuk semua jenis desimal yang dipetakan ke db.

Tokek IT
sumber
Itu tidak bekerja sampai Remove<DecimalPropertyConvention>();datang sebelum Add(new DecimalPropertyConvention(18, 4));. Saya pikir itu aneh bahwa tidak hanya ditimpa secara otomatis.
Mike de Klerk
2

Menggunakan

System.ComponentModel.DataAnnotations;

Anda cukup menaruh atribut itu di model Anda:

[DataType("decimal(18,5)")]
VinnyG
sumber
1
ini adalah implementasi termudah untuk keterbacaan dan kesederhanaan. IMHO
ransem
11
Per msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx , jawaban ini secara faktual salah. "Jangan bingung atribut TypeName Kolom dengan DataType DataAnnotation. DataType adalah anotasi yang digunakan untuk UI dan diabaikan oleh Kode Pertama."
speckledcarp
2
@ Transem Saya pikir juga begitu, sampai saya baru saja mengujinya dan seperti yang dikatakan di atas, ini tidak berfungsi untuk CodeFirst dan tidak bermigrasi ke database
RoLYroLLs
1

Anda dapat menemukan informasi lebih lanjut tentang MSDN - segi Model Data Entitas. http://msdn.microsoft.com/en-us/library/ee382834.aspx Direkomendasikan penuh.

Jaider
sumber
Itu hebat dan semuanya, tetapi bagaimana hubungannya dengan Code-First?
Dave Van den Eynde
Ini berguna tetapi saya tidak bisa menentukan atribut [Presisi] untuk desimal. Jadi saya menggunakan solusi yang disediakan oleh @KinSlayerUY.
Colin
1

Sebenarnya untuk EntityFrameworkCore 3.1.3:

beberapa solusi di OnModelCreating:

var fixDecimalDatas = new List<Tuple<Type, Type, string>>();
foreach (var entityType in builder.Model.GetEntityTypes())
{
    foreach (var property in entityType.GetProperties())
    {
        if (Type.GetTypeCode(property.ClrType) == TypeCode.Decimal)
        {
            fixDecimalDatas.Add(new Tuple<Type, Type, string>(entityType.ClrType, property.ClrType, property.GetColumnName()));
        }
    }
}

foreach (var item in fixDecimalDatas)
{
    builder.Entity(item.Item1).Property(item.Item2, item.Item3).HasColumnType("decimal(18,4)");
}

//custom decimal nullable:
builder.Entity<SomePerfectEntity>().Property(x => x.IsBeautiful).HasColumnType("decimal(18,4)");
Azamat
sumber
0

Atribut khusus KinSlayerUY bekerja dengan baik untuk saya, tetapi saya memiliki masalah dengan ComplexTypes. Mereka dipetakan sebagai entitas dalam kode atribut sehingga tidak dapat dipetakan sebagai ComplexType.

Karena itu saya memperpanjang kode untuk memungkinkan ini:

public static void OnModelCreating(DbModelBuilder modelBuilder)
    {
        foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAttribute)).GetTypes()
                                   where t.IsClass && t.Namespace == "FA.f1rstval.Data"
                                   select t)
        {
            foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<DecimalPrecisionAttribute>() != null).Select(
                   p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) }))
            {

                ParameterExpression param = ParameterExpression.Parameter(classType, "c");
                Expression property = Expression.Property(param, propAttr.prop.Name);
                LambdaExpression lambdaExpression = Expression.Lambda(property, true,
                                                                         new ParameterExpression[] { param });
                DecimalPropertyConfiguration decimalConfig;
                int MethodNum;
                if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    MethodNum = 7;
                }
                else
                {
                    MethodNum = 6;
                }

                //check if complextype
                if (classType.GetCustomAttribute<ComplexTypeAttribute>() != null)
                {
                    var complexConfig = modelBuilder.GetType().GetMethod("ComplexType").MakeGenericMethod(classType).Invoke(modelBuilder, null);
                    MethodInfo methodInfo = complexConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[MethodNum];
                    decimalConfig = methodInfo.Invoke(complexConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
                }
                else
                {
                    var entityConfig = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(classType).Invoke(modelBuilder, null);
                    MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[MethodNum];
                    decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
                }

                decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
            }
        }
    }
Mark007
sumber
0

@ Mark007, saya telah mengubah kriteria pemilihan jenis untuk naik dari properti DbSet <> dari DbContext. Saya pikir ini lebih aman karena ada kalanya Anda memiliki kelas di namespace yang diberikan yang seharusnya tidak menjadi bagian dari definisi model atau mereka tetapi bukan entitas. Atau entitas Anda dapat berada di ruang nama atau majelis yang terpisah dan ditarik bersama menjadi satu Konteks sekali.

Juga, meskipun tidak mungkin, saya tidak berpikir itu aman untuk mengandalkan pemesanan definisi metode, jadi lebih baik menariknya dengan daftar Parameter. (.GetTypeMethods () adalah metode ekstensi yang saya bangun untuk bekerja dengan paradigma TypeInfo baru dan dapat meratakan hierarki kelas saat mencari metode).

Perhatikan bahwa OnModelCreating mendelegasikan metode ini:

    private void OnModelCreatingSetDecimalPrecisionFromAttribute(DbModelBuilder modelBuilder)
    {
        foreach (var iSetProp in this.GetType().GetTypeProperties(true))
        {
            if (iSetProp.PropertyType.IsGenericType
                    && (iSetProp.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>) || iSetProp.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)))
            {
                var entityType = iSetProp.PropertyType.GetGenericArguments()[0];

                foreach (var propAttr in entityType
                                        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                        .Select(p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) })
                                        .Where(propAttr => propAttr.attr != null))
                {
                    var entityTypeConfigMethod = modelBuilder.GetType().GetTypeInfo().DeclaredMethods.First(m => m.Name == "Entity");
                    var entityTypeConfig = entityTypeConfigMethod.MakeGenericMethod(entityType).Invoke(modelBuilder, null);

                    var param = ParameterExpression.Parameter(entityType, "c");
                    var lambdaExpression = Expression.Lambda(Expression.Property(param, propAttr.prop.Name), true, new ParameterExpression[] { param });

                    var propertyConfigMethod =
                        entityTypeConfig.GetType()
                            .GetTypeMethods(true, false)
                            .First(m =>
                            {
                                if (m.Name != "Property")
                                    return false;

                                var methodParams = m.GetParameters();

                                return methodParams.Length == 1 && methodParams[0].ParameterType == lambdaExpression.GetType();
                            }
                            );

                    var decimalConfig = propertyConfigMethod.Invoke(entityTypeConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;

                    decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
                }
            }
        }
    }



    public static IEnumerable<MethodInfo> GetTypeMethods(this Type typeToQuery, bool flattenHierarchy, bool? staticMembers)
    {
        var typeInfo = typeToQuery.GetTypeInfo();

        foreach (var iField in typeInfo.DeclaredMethods.Where(fi => staticMembers == null || fi.IsStatic == staticMembers))
            yield return iField;

        //this bit is just for StaticFields so we pass flag to flattenHierarchy and for the purpose of recursion, restrictStatic = false
        if (flattenHierarchy == true)
        {
            var baseType = typeInfo.BaseType;

            if ((baseType != null) && (baseType != typeof(object)))
            {
                foreach (var iField in baseType.GetTypeMethods(true, staticMembers))
                    yield return iField;
            }
        }
    }
Eniola
sumber
Saya baru sadar saya tidak berurusan dengan ComplexTypes dengan pendekatan ini. Akan merevisinya nanti.
Eniola
Namun, solusi yang diajukan oleh Brian sederhana, elegan dan bekerja. Saya tidak akan membuat pernyataan kategoris tentang kinerja tetapi naik sudah mencerminkan PropertyInfo daripada memburu Anda harus menghasilkan kinerja yang lebih baik pada model yang sangat besar (dalam urutan 200 ke atas).
Eniola