Önce EF Kodunda ondalık hassasiyet ve ölçek


230

Bu kod ilk yaklaşım ile deniyorum, ama şimdi System.Decimal türü bir özellik türü ondalık (18, 0) bir sql sütun eşlenir olduğunu öğrendim.

Veritabanı sütununun hassasiyetini nasıl ayarlarım?


11
bir yol [Column(TypeName = "decimal(18,4)")]ondalık özellikleriniz için öznitelik kullanmaktır
S.Serpooshan

[Sütun (TypeName = "ondalık (18,4)")] harika çalıştı !!!
Brian Rice

Yanıtlar:


257

Dave Van den Eynde'nin yanıtı artık güncel değil. EF 4.1'den itibaren ModelBuilder sınıfı artık DbModelBuilder ve imzası olan bir DecimalPropertyConfiguration.HasPrecision Yöntemi var: 2 önemli değişiklik var:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

Burada kesinlik, ondalık noktanın nereye düştüğüne ve ölçeğin saklayacağı ondalık basamak sayısına bakılmaksızın, db'nin depolayacağı toplam basamak sayısıdır.

Bu nedenle, gösterildiği gibi özellikleri yinelemeye gerek yoktur, ancak

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

DbModelBuilder ile ilgili sorunlar yaşayan herkes için deneyinSystem.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
Lloyd Powell

1
Hiç aramadýđýný fark ettim base.OnModelCreating(modelBuilder);. Bu kasıtlı mı yoksa sadece IDE yerine çevrimiçi kod yazmanın kurbanı mıydı?
BenSwayne

1
@BenSwayne spot için teşekkürler, bu benim ihmal, kasıtlı bir şey değil. Cevabı düzenleyeceğim.
AlexC

26
HasPrecision için 2 argüman (kesinlik, ölçek) zayıf bir şekilde belgelenmiştir. duyarlık, ondalık noktasının nereye düştüğüne bakılmaksızın depolayacağı toplam basamak sayısıdır. ölçek, saklayacağı ondalık basamak sayısıdır.
Chris Moschini

1
Tek bir yerde tüm varlıkların tüm ondalık özelliklerini ayarlamak için bir EF yapılandırması var mı? Genellikle kullanırız (19,4). Bunun tüm ondalık özelliklere otomatik olarak uygulanması iyi olurdu, bu nedenle hesaplamalarda bir özellik hassasiyeti ayarlamayı ve beklenen hassasiyeti kaçırmayı unutamayız.
Mike de Klerk

89

decimalsEF6'daki herkes için hassasiyeti ayarlamak isterseniz, aşağıdakilerde DecimalPropertyConventionkullanılan varsayılan sözleşmeyi değiştirebilirsiniz DbModelBuilder:

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

DecimalPropertyConventionEF6'daki varsayılan decimalözellikler özellikleridecimal(18,2) sütunlarla .

Tek tek özelliklerin belirli bir kesinliğe sahip olmasını istiyorsanız, kuruluşun özelliğine ilişkin hassasiyeti aşağıdakiler üzerinde ayarlayabilirsiniz DbModelBuilder:

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

Veya, EntityTypeConfiguration<>kesinlik düzeyini belirten varlık için bir ekleyin :

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

1
En sevdiğim çözüm. CodeFirst ve geçişleri kullanırken mükemmel çalışır: EF, "ondalık" ın kullanıldığı tüm sınıflardaki tüm özellikleri arar ve bu özellikler için bir taşıma oluşturur. Harika!
okieh

75

Bunun için bir Özel Özellik oluşturmak için güzel bir zaman geçirdim:

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

}

böyle kullanmak

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

ve sihir, model oluşturmada biraz yansımayla olur

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

ilk bölüm modeldeki tüm sınıfları elde etmektir (benim özel özniteliği bu derlemede tanımlanır, bu yüzden modelle derlemeyi almak için kullanılır)

ikinci foreach özel öznitelik ve özniteliğin kendisi ile bu sınıftaki tüm özellikleri alır, böylece hassasiyet ve ölçek verilerini alabilirim

ondan sonra aramam gerek

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

bu yüzden yansıma ile modelBuilder.Entity () çağırmak ve entityConfig değişkeninde saklamak sonra "c => c.PROPERTY_NAME" lambda ifade oluşturmak

Bundan sonra, ondalık sıfırlanabilir ise

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

yöntemi (i dizideki pozisyona göre bu, biliyorum ideal değil, herhangi bir yardım çok takdir edilecektir)

ve boş bırakılmazsa

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

yöntem.

DecimalPropertyConfiguration i olan HasPrecision yöntemini çağırıyorum.


3
Bunun için teşekkürler. Beni binlerce lambda ifadesi üretmekten kurtardı.
Sean

1
Bu harika çalışıyor ve süper temiz! EF 5 için System.Data.Entity.ModelConfiguration.ModelBuilder öğesini System.Data.Entity.DbModelBuilder olarak değiştirdim
Colin

3
MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });doğru aşırı yük almak için kullanın . şimdiye kadar çalışıyor gibi görünüyor.
fscan

3
Bunu bir kütüphaneye tamamladım ve DbContext'den çağrı yapmayı kolaylaştırdım: github.com/richardlawley/EntityFrameworkAttributeConfig (nuget aracılığıyla da mevcut)
Richard

Richard, projenizin fikrini seviyorum ama EF6 gerektiren bir şey var mı? EF5 uyumlu bir sürüm olsaydı, ODP.NET sürümümle kullanabilseydim.
Patrick Szalapski

50

Kullanılması DecimalPrecisonAttributeKinSlayerUY gelen Ef6 size (ayar aksine özniteliği bireysel özelliklerini idare edecek bir kongre oluşturabilir DecimalPropertyConventionolduğu gibi bu cevap tüm ondalık özelliklerini etkileyecektir).

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

Sonra DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}

@MichaelEdenfield Aslında EF6'da bunlardan biri yok. Bu yüzden, iki cevap ekledim, bu ve sizin bahsettiğiniz diğer cevap. Bu, modeldeki tüm ondalık özellikleri etkilemek yerine tek bir ondalık özellik üzerine koyabileceğiniz bir özelliktir.
kjbartel

benim kötüm, ikisini de yazdığını fark etmedim: \
Michael Edenfield

1
Sınır kontrolüne gidecekseniz Precision, üst sınırı 28'e ayarlamanız önerilir (böylece > 28durumunuzda). MSDN belgelerine göre System.Decimal, yalnızca maksimum 28-29 basamaklı hassasiyeti temsil edebilir ( msdn.microsoft.com/en-us/library/364x0z75.aspx ). Ayrıca, öznitelik Scaleolarak bildirilir byte, yani önkoşulunuz attribute.Scale < 0gereksizdir.
NathanAldenSr

2
@kjbartel Bazı veritabanı sağlayıcılarının 28'den büyük kesimleri desteklediği doğrudur; Ancak, MSDN'ye göre System.Decimaldeğil. Bu nedenle, üst sınır ön koşulunu 28'den büyük herhangi bir şeye ayarlamak mantıklı değildir; System.DecimalGörünüşe göre bu kadar büyük sayıları temsil edemez. Ayrıca, bu özniteliğin SQL Server dışındaki veri sağlayıcıları için yararlı olduğunu unutmayın. Örneğin, PostgreSQL'in numerictürü 131072 basamağa kadar hassasiyeti destekler.
NathanAldenSr

1
Dediğim gibi, veritabanları bir sabit nokta ondalık ( msdn ) kullanırken System.Decimal kayan nokta . Tamamen farklılar. Örneğin, bir decimal(38,9)sütuna sahip olmak mutlu olacak, System.Decimal.MaxValueancak bir decimal(28,9)sütun olmayacaktır. Hassasiyeti sadece 28 ile sınırlamak için bir neden yoktur.
kjbartel

47

Görünüşe göre, DbContext.OnModelCreating () yöntemini geçersiz kılabilir ve hassasiyeti şu şekilde yapılandırabilirsiniz:

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

Ama bu fiyat ile ilgili tüm özellikleri ile yapmak zorunda oldukça sıkıcı bir kod, bu yüzden bu ile geldi:

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

Temel uygulama hiçbir şey yapmasa bile, bir yöntemi geçersiz kıldığınızda temel yöntemi çağırmanız iyi bir uygulamadır.

Güncelleme: Bu makale de çok yardımcı oldu.


10
Teşekkürler, bu bana doğru yönü gösterdi. CTP5'te sözdizimi, aynı ifadede Kesinlik ve Ölçek eklenmesine izin verecek şekilde değişti: modelBuilder.Entity <Product> () .Property (product => product.Price) .HasPrecision (6, 2);
Col

2
Yine de, tüm ondalık sayılar için ayarlayabileceğiniz bir çeşit "varsayılan" olması iyi olmaz mıydı ?
Dave Van den Eynde

3
Aramanın base.OnModelCreating(modelBuilder);gerekli olduğunu düşünmüyorum . VS'deki DbContext meta verilerinden: 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: Güzel, ama bir uygulayıcı olarak bunu önemsememeli ve her zaman üssü aramalıyım.
Dave Van den Eynde

@ Dave ve @Matt: Baz aramak için "ÖNEMLİ" bir yorum vardı. İyi bir uygulamadır, ancak EF kaynağının boş bir uygulaması olduğunda, Önemli olduğunu iddia etmek yanıltıcıdır. Bu, insanların üsün ne yaptığını merak etmesini sağlar. Ben kontrol etmek için ef5.0 için ayrıştırılmış ÖNEMLİ ne olduğunu çok merak ediyordum. Orada hiçbir şey yok. Sadece iyi bir alışkanlık.
phil soady


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

bu, burada açıklandığı gibi EF Core kodu ilk geçişleriyle çalışır .


1
Bunu sadece modelinize eklerseniz, alabilirsinizThe store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
Savage

@Savage, veritabanı sağlayıcınızla veya veritabanı sürümüyle ilgili bir sorun gibi görünüyor
Elnoor

@Elnoor Savage doğru, bu EF Migrations 6.x'te bir hata verecektir. Eski Çekirdek olmayan sürüm, Sütun özniteliği aracılığıyla kesinlik / ölçek belirtmeyi desteklemez ve DataType özniteliğini kullanırsanız hiçbir şey yapmaz (varsayılanı 18,2'dir). EF 6.x'te Attribute aracılığıyla çalışmasını sağlamak için ModelBuilder'a kendi uzantınızı uygulamanız gerekir.
Chris Moschini

1
@ChrisMoschini, EF Core'dan bahsettiğim cevabımı değiştirdim. Teşekkürler
Elnoor

14

bu kod satırı aynı şeyi başarmanın daha kolay bir yolu olabilir:

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

9

- EF CORE İÇİN - ile System.ComponentModel.DataAnnotations kullanarak;

kullanım [Column( TypeName = "decimal( hassasiyet , ölçek )")]

Hassasiyet = Kullanılan toplam karakter sayısı

Ölçek = Noktadan sonraki toplam sayı. (kafası karışması kolay)

Örnek :

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

Daha fazla ayrıntı burada: https://docs.microsoft.com/tr-tr/ef/core/modeling/relational/data-types


3

EF6'da

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

Bu cevap, niteliği tanımlayan başka bir cevaba yükseltme gibi görünüyor, bunu bu cevaba düzenlemelisiniz
Rhys Bevilaqua

3

EF'e her zaman OnModelCreating işlevindeki Context sınıfındaki kurallarla bunu yapmasını söyleyebilirsiniz:

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

Bu yalnızca Code First EF fyi için geçerlidir ve db ile eşlenen tüm ondalık türler için geçerlidir.


Remove<DecimalPropertyConvention>();Önce gelene kadar çalışma değildi Add(new DecimalPropertyConvention(18, 4));. Bence sadece otomatik olarak geçersiz kılmamak garip.
Mike de Klerk

2

kullanma

System.ComponentModel.DataAnnotations;

Bu özelliği modelinize yerleştirebilirsiniz:

[DataType("decimal(18,5)")]

1
okunabilirlik ve basitlik için en kolay uygulama budur. IMHO
fidye

11
Msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx uyarınca , bu cevap aslında yanlıştır. "Sütunun TypeName özniteliğini DataType DataAnnotation ile karıştırmayın. DataType, UI için kullanılan bir ek açıklamadır ve İlk Kod tarafından yoksayılır."
speckledcarp

2
@ransems Ben de öyle düşündüm, ben sadece test kadar ve yukarıda söylendiği gibi, bu CodeFirst için işe yaramaz ve veritabanına göç etmez
RoLYroLLs


1

EntityFrameworkCore 3.1.3 için gerçek:

OnModelCreating'de bazı çözümler:

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)");

0

KinSlayerUY'nin özel özelliği benim için iyi çalıştı ancak ComplexTypes ile ilgili sorunlar yaşadım. Özellik kodundaki varlıklar olarak eşleniyorlardı, bu nedenle bir ComplexType olarak eşlenemediler.

Bu nedenle buna izin vermek için kodu genişletti:

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

0

@ Mark007, DbContext DbSet <> özelliklerine binmek için tür seçim ölçütlerini değiştirdim. Bu daha güvenli olduğunu düşünüyorum çünkü verilen ad alanında model tanımının bir parçası olmamalı ya da varlık olmayan sınıflara sahip olduğunuz zamanlar vardır. Veya varlıklarınız ayrı ad alanlarında veya ayrı montajlarda bulunabilir ve bir kez Bağlam'a çekilebilir.

Ayrıca, olası olmasa da, yöntem tanımlarının sırasına güvenmenin güvenli olduğunu düşünmüyorum, bu yüzden onları Parametre listesiyle çıkarmak daha iyidir. (.GetTypeMethods (), yeni TypeInfo paradigmasıyla çalışmak için oluşturduğum ve yöntemler ararken sınıf hiyerarşilerini düzleştirebilen bir uzantı yöntemidir).

OnModelCreating'in bu yönteme delege ettiğini unutmayın:

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

Bu yaklaşımla ComplexTypes ile ilgilenmediğimi fark ettim. Daha sonra gözden geçireceğim.
Eniola

Ancak, Brian tarafından önerilen çözüm basit, zarif ve işe yarıyor. Performansla ilgili herhangi bir kategorik açıklama yapmayacağım, ancak sizinkini avlamak yerine zaten yansıtılmış PropertyInfo'yu kullanmak çok büyük modellerde (200 ve üstü sırada) daha iyi performans vermelidir.
Eniola
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.