EF 코드의 십진 정밀도 및 스케일


230

이 코드 우선 접근 방식을 실험하고 있지만 System.Decimal 유형의 속성이 decimal (18, 0) 유형의 SQL 열에 매핑된다는 것을 알게되었습니다.

데이터베이스 열의 정밀도를 어떻게 설정합니까?


11
한 가지 방법은 [Column(TypeName = "decimal(18,4)")]10 진수 속성에 속성 을 사용하는 것입니다
S.Serpooshan

[Column (TypeName = "decimal (18,4)")] 잘 작동했습니다 !!!
Brian Rice

답변:


257

Dave Van den Eynde의 답변이 구식입니다. EF 4.1부터 ModelBuilder 클래스는 이제 DbModelBuilder 이고 다음과 같은 서명을 갖는 DecimalPropertyConfiguration.HasPrecision 메소드가 있습니다.

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

여기서 precision은 소수점이 떨어지는 위치에 관계없이 db가 저장할 총 자릿수이고 scale은 저장할 소수점 이하 자릿수입니다.

따라서 표시된대로 속성을 반복 할 필요는 없지만에서 호출 할 수 있습니다

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 문제를지고 누군가를 위해, 시도System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
로이드 파월

1
나는 당신이 결코 전화하지 않았다는 것을 알아 차렸다 base.OnModelCreating(modelBuilder);. IDE가 아닌 온라인에서 코드를 입력하는 것이 의도적이거나 단순한 희생자입니까?
BenSwayne

1
@ BenSwayne 그 자리에 감사드립니다, 이것은 의도적 인 것이 아니라 내 누락입니다. 답을 편집하겠습니다.
AlexC

26
HasPrecision (precision, scale)에 대한 두 가지 주장은 제대로 문서화되지 않았습니다. 정밀도는 소수점 위치에 관계없이 저장할 총 자릿수입니다. scale은 저장할 소수점 이하 자릿수입니다.
Chris Moschini

1
한 곳에서 모든 엔터티에 대한 모든 10 진수 속성에 대해 설정하는 EF 구성이 있습니까? 우리는 일반적으로 (19,4)를 사용합니다. 이것을 모든 10 진수 속성에 자동으로 적용하는 것이 좋으므로 속성 정밀도를 설정하는 것을 잊을 수 없으며 계산에서 예상 정밀도를 놓칠 수 없습니다.
Mike de Klerk

89

모두의 정밀도를 설정하려면 decimalsEF6에서 에서 DecimalPropertyConvention사용되는 기본 규칙을 대체 하십시오 DbModelBuilder.

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

DecimalPropertyConventionEF6 의 기본값 은 decimal속성을 decimal(18,2)열에 매핑 합니다 .

개별 속성 만 지정된 정밀도를 가지려면 개체 속성의 정밀도를 DbModelBuilder .

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

또는 EntityTypeConfiguration<>정밀도를 지정하는 엔티티에 for를 추가하십시오 .

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
내가 가장 좋아하는 솔루션. CodeFirst 및 마이그레이션을 사용할 때 완벽하게 작동합니다. EF는 "소수"가 사용되는 모든 클래스에서 모든 속성을 찾고 이러한 속성에 대한 마이그레이션을 생성합니다. 큰!
okieh

75

나는 이것을 위해 커스텀 속성을 만드는 것이 즐거웠다.

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

}

이런 식으로 사용

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

마법은 약간의 반성과 함께 모델을 만들 때 발생합니다

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

첫 번째 부분은 모델의 모든 클래스를 얻는 것입니다 (사용자 정의 속성은 해당 어셈블리에 정의되어 있으므로 모델과 함께 어셈블리를 얻는 데 사용했습니다)

두 번째 foreach는 사용자 정의 속성을 사용하여 해당 클래스의 모든 속성과 속성 자체를 가져 오기 때문에 정밀도 및 스케일 데이터를 얻을 수 있습니다

그 후 나는 전화해야

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

리플렉션을 통해 modelBuilder.Entity ()를 호출하고 entityConfig 변수에 저장 한 다음 "c => c.PROPERTY_NAME"람다 식을 빌드합니다.

그 후, 10 진수가 nullable이면

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

방법 (배열의 위치로 이것을 호출합니다. 이상적이지 않습니다. 어떤 도움을 주시면 감사하겠습니다)

그리고 nullable이 아닌 경우

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

방법.

DecimalPropertyConfiguration을 사용하면 HasPrecision 메서드를 호출합니다.


3
고마워 수천 개의 람다 식을 생성하지 못했습니다.
Sean

1
이것은 훌륭하게 작동하며 매우 깨끗합니다! EF 5의 경우 System.Data.Entity.ModelConfiguration.ModelBuilder를 System.Data.Entity.DbModelBuilder
Colin으로

3
MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });올바른 과부하를 얻는 데 사용 합니다. 지금까지 작동하는 것 같습니다.
fscan

3
나는 이것을 라이브러리에 싸서 DbContext에서 쉽게 호출 할 수있게했다 : github.com/richardlawley/EntityFrameworkAttributeConfig (nuget을 통해 사용 가능)
Richard

리차드, 나는 당신의 프로젝트 아이디어를 좋아하지만 EF6가 필요한 프로젝트가 있습니까? EF5 호환 버전이 있으면이를 사용하여 내 ODP.NET 버전과 함께 사용할 수 있습니다.
Patrick Szalapski

50

DecimalPrecisonAttributefrom KinSlayerUY를 사용하여 EF6에서 속성을 갖는 개별 속성을 처리하는 규칙을 만들 수 있습니다 ( 이 답변DecimalPropertyConvention 에서 이와 같은 설정은 모든 십진수 속성에 영향을 미침).

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

그런 다음에 DbContext:

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

@MichaelEdenfield 실제로 EF6에는 이들 중 하나가 없습니다. 따라서 두 가지 답변을 추가했습니다.이 답변과 다른 답변이 추가되었습니다. 이것은 모델의 모든 10 진수 속성에 영향을주는 것이 아니라 단일 10 진수 속성에 넣을 수있는 속성입니다.
kjbartel

내 나쁜, 당신이 그들 모두를 썼다 통지를하지 않았다 : \
마이클 Edenfield에게

1
bounds-check Precision하려는 경우 상한을 28로 설정하는 것이 좋습니다 (따라서 > 28조건에 따라). MSDN 설명서에 따르면 System.Decimal최대 28-29 자리의 정밀도 ( msdn.microsoft.com/en-us/library/364x0z75.aspx ) 만 나타낼 수 있습니다 . 또한이 속성은 Scale로 선언 되므로 byte전제 조건 attribute.Scale < 0이 필요하지 않습니다.
NathanAldenSr

2
@kjbartel 일부 데이터베이스 공급자는 28보다 큰 정밀도를 지원합니다. 그러나 MSDN에 따르면 System.Decimal그렇지 않습니다. 따라서 상한 전제 조건을 28보다 큰 것으로 설정하는 것은 의미가 없습니다. System.Decimal분명히 큰 숫자를 나타낼 수 없습니다. 또한이 특성은 SQL Server 이외의 데이터 공급자에 유용합니다. 예를 들어 PostgreSQL numeric유형은 최대 131072 자릿수의 정밀도를 지원합니다.
NathanAldenSr

1
@NathanAldenSr 앞에서 말했듯이 데이터베이스는 고정 소수점 10 진수 ( msdn )를 사용하는 반면 System.Decimal은 부동 소수점 입니다. 그들은 완전히 다릅니다. 예를 들어 decimal(38,9)열이 있으면 유지 System.Decimal.MaxValue되지만 decimal(28,9)열은 유지되지 않습니다. 정밀도를 28로 제한 할 이유는 없습니다.
kjbartel

47

분명히 DbContext.OnModelCreating () 메서드를 재정의하고 다음과 같이 정밀도를 구성 할 수 있습니다.

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

그러나 이것은 모든 가격 관련 속성으로해야 할 때 매우 지루한 코드이므로 다음과 같이 생각해 냈습니다.

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

기본 구현이 아무 것도 수행하지 않더라도 메서드를 재정의 할 때 기본 메서드를 호출하는 것이 좋습니다.

업데이트 : 이 기사 는 매우 도움이되었습니다.


10
고마워, 이것은 올바른 방향으로 나를 지적했다. CTP5에서 구문은 같은 명령문에 Precision 및 Scale을 추가 할 수 있도록 변경되었습니다. modelBuilder.Entity <Product> (). Property (product => product.Price) .HasPrecision (6, 2);
Col

2
그래도 모든 소수에 대해 설정할 수있는 일종의 "기본"을 갖는 것이 좋지 않습니까?
Dave Van den Eynde

3
전화 base.OnModelCreating(modelBuilder);가 필요 하다고 생각하지 않습니다 . VS의 DbContext 메타 데이터에서 : 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

@ 매트 : 그것은 훌륭하지만 구현 자로 나는 이것에 신경 쓰지 않아야하며 항상베이스를 호출해야합니다.
Dave Van den Eynde

@ Dave와 @Matt : 전화를 거는 것이 "중요"라는 의견이있었습니다. 모범 사례이지만 EF 소스에 빈 구현이있는 경우 중요하다고 주장하는 것은 잘못된 것입니다. 그것은 사람들이 기지가 무엇을하는지 궁금하게 만듭니다. 중요한 점이 무엇인지 궁금해서 확인하기 위해 ef5.0으로 디 컴파일했습니다. 아무것도 없습니다. 좋은 습관입니다.
필 콩


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

이것은 여기에 설명 된대로 EF Core 코드 첫 번째 마이 그 레이션에서 작동 합니다 .


1
이것을 모델에 추가하면 다음을 얻을 수 있습니다The store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
Savage

@Savage는 데이터베이스 제공 업체 또는 데이터베이스 버전에 문제가있는 것으로 보입니다
Elnoor

@Elnoor Savage가 정확하면 EF Migrations 6.x에서 오류가 발생합니다. 레거시 비 Core 버전은 Column 속성을 통한 정밀도 / 스케일 지정을 지원하지 않으며 DataType 속성을 사용하는 경우 아무 것도 설정하지 않습니다 (기본값은 18,2). EF 6.x에서 속성을 통해 작동하게하려면 ModelBuilder에 대한 자체 확장을 구현해야합니다.
Chris Moschini

1
@ChrisMoschini, EF Core에 대한 답변을 변경했습니다. 감사합니다
Elnoor

14

이 코드 라인은 동일한 것을 달성하는 더 간단한 방법이 될 수 있습니다.

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

9

- EF 코어 - System.ComponentModel.DataAnnotations 사용합니다.

사용 [Column( TypeName = "decimal( 정밀도 , 스케일 )")]

정밀도 = 사용 된 총 문자 수

스케일 = 점 뒤의 총 수입니다. (혼란하기 쉬움)

:

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

자세한 내용은 https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-types를 참조하십시오.


3

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

이 답변은 속성을 정의하는 다른 답변으로의 업그레이드 인 것 같습니다. 해당 답변으로 편집해야합니다.
Rhys Bevilaqua

3

다음과 같이 EF에게 OnModelCreating 함수의 Context 클래스에서 규칙을 사용하여이를 수행하도록 항상 지시 할 수 있습니다.

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

이는 Code First EF fyi에만 적용되며 db에 매핑 된 모든 10 진수 유형에 적용됩니다.


Remove<DecimalPropertyConvention>();앞에 올 때까지 작동하지 않았습니다 Add(new DecimalPropertyConvention(18, 4));. 자동으로 재정의되지 않는 것이 이상하다고 생각합니다.
Mike de Klerk

2

사용

System.ComponentModel.DataAnnotations;

모델에 해당 속성을 넣을 수 있습니다.

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

1
가독성과 단순성을위한 가장 쉬운 구현입니다. IMHO
ransems

11
msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx ,이 답변이 사실로 올바르지 않습니다. "컬럼의 TypeName 속성을 DataType DataAnnotation과 혼동하지 마십시오. DataType은 UI에 사용되는 주석이며 Code First에서 무시됩니다."
speckledcarp

2
@ransems 나도 그것을 테스트 할 때까지 그렇게 생각했고 위에서 언급했듯이 이것은 CodeFirst에서 작동하지 않으며 데이터베이스로 마이그레이션되지 않습니다.
RoLYroLLs


1

EntityFrameworkCore 3.1.3의 경우 :

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

0

KinSlayerUY의 커스텀 속성은 훌륭하게 작동했지만 ComplexTypes에 문제가있었습니다. 속성 코드에서 엔티티로 맵핑되었으므로 ComplexType으로 맵핑 할 수 없었습니다.

따라서이를 위해 코드를 확장했습니다.

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 <> 속성을 ​​사용하도록 변경했습니다. 주어진 네임 스페이스에 모델 정의의 일부가 아니거나 엔티티가 아닌 클래스가있는 시간이 있기 때문에 이것이 더 안전하다고 생각합니다. 또는 엔터티가 별도의 네임 스페이스 또는 별도의 어셈블리에있을 수 있으며 한 컨텍스트로 결합 될 수 있습니다.

또한 가능하지는 않지만 메소드 정의의 순서에 의존하는 것이 안전하지 않다고 생각하므로 매개 변수 목록으로 가져 오는 것이 좋습니다. (.GetTypeMethods ()는 새로운 TypeInfo 패러다임과 함께 작동하도록 개발 된 확장 메서드이며 메서드를 찾을 때 클래스 계층 구조를 병합 할 수 있습니다).

OnModelCreating은이 메소드에 위임합니다.

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

나는이 접근법으로 ComplexTypes를 다루지 않았다는 것을 깨달았습니다. 나중에 수정하겠습니다.
Eniola

그러나 Brian 이 제안한 솔루션 은 간단하고 우아하며 작동합니다. 나는 성능에 대한 범주 적 진술을하지는 않지만 당신의 것을 사냥하는 것보다 이미 PropertyInfo를 반영하는 것은 매우 큰 모델 (200 이상)에서 더 나은 성능을 제공해야합니다.
Eniola
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.