[C#] EF 코드의 십진 정밀도 및 스케일

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

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



답변

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


답변

모두의 정밀도를 설정하려면 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);
    }
}


답변

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

[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 메서드를 호출합니다.


답변

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


답변

분명히 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);
    }

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

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


답변

Entity Framework Ver 6 (Alpha, rc1)에는 Custom Conventions 라는 것이 있습니다. 소수 자릿수를 설정하려면

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

참고:


답변

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

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