Десятичная точность и масштаб в EF Code First - PullRequest
205 голосов
/ 17 августа 2010

Я экспериментирую с этим первым подходом к коду, но теперь выясняю, что свойство типа System.Decimal отображается на столбец sql типа decimal (18, 0).

Как настроить точность столбца базы данных?

Ответы [ 15 ]

2 голосов
/ 24 августа 2016

Вы всегда можете сказать EF сделать это с соглашениями в классе Context в функции OnModelCreating следующим образом:

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 и применяется ко всем десятичным типам, сопоставленным с БД.

1 голос
/ 10 марта 2017

Использование

System.ComponentModel.DataAnnotations;

Вы можете просто добавить этот атрибут в вашу модель:

[DataType("decimal(18,5)")]
1 голос
/ 09 июня 2011

Более подробную информацию вы можете найти в MSDN - аспекте Entity Data Model.http://msdn.microsoft.com/en-us/library/ee382834.aspx Полный рекомендуется.

0 голосов
/ 23 октября 2014

@ Mark007, я изменил критерии выбора типа, чтобы использовать свойства DbSet <> DbContext.Я думаю, что это безопаснее, потому что бывают случаи, когда в данном пространстве имен есть классы, которые не должны быть частью определения модели или они не являются сущностями.Или ваши сущности могут находиться в отдельных пространствах имен или отдельных сборках и объединяться в один и тот же контекст.

Кроме того, хотя это маловероятно, я не считаю безопасным полагаться на упорядочение определений методов, поэтому лучше использоватьих с помощью списка параметров.(.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;
            }
        }
    }
0 голосов
/ 12 августа 2014

Пользовательский атрибут KinSlayerUY работал хорошо для меня, но у меня были проблемы с ComplexTypes.Они были сопоставлены как сущности в коде атрибута, поэтому их нельзя было сопоставить как ComplexType.

Поэтому я расширил код, чтобы учесть это:

...