Десятичная точность и масштаб в EF Code First

230

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

Как мне установить точность столбца базы данных?

Дэйв Ван ден Эйнде
источник
11
Одним из способов является использование [Column(TypeName = "decimal(18,4)")]атрибута для ваших десятичных свойств
S.Serpooshan
[Column (TypeName = "decimal (18,4)")] работал отлично !!!
Брайан Райс

Ответы:

257

Ответ от Дейва Ван ден Эйнде сейчас устарел. Есть 2 важных изменения, начиная с EF 4.1 и далее, класс ModelBuilder теперь называется DbModelBuilder, и теперь существует метод DecimalPropertyConfiguration.HasPrecision, имеющий сигнатуру:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte 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);
   }
}
AlexC
источник
Для тех, кто испытывает проблемы с DbModelBuilder, попробуйтеSystem.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
Ллойд Пауэлл
1
Я заметил, что ты никогда не звонил base.OnModelCreating(modelBuilder);. Было ли это намеренно или просто жертвой ввода кода онлайн вместо IDE?
BenSwayne
1
@BenSwayne спасибо за место, это мое упущение, а не что-то преднамеренное. Я отредактирую ответ.
AlexC
27
2 аргумента HasPrecision (точность, масштаб) плохо документированы. точность - это общее количество цифр, которые оно будет хранить, независимо от того, где находится десятичная точка. шкала - это количество десятичных разрядов, которые оно будет хранить.
Крис Москини
1
Существует ли конфигурация EF для установки всех десятичных свойств всех объектов в одном месте? Мы обычно используем (19,4). Было бы хорошо, чтобы это автоматически применялось ко всем десятичным свойствам, поэтому мы не можем забыть установить точность свойства и упустить ожидаемую точность в вычислениях.
Майк де Клерк
89

Если вы хотите установить точность для всех decimalsв EF6, вы можете заменить DecimalPropertyConventionсоглашение по умолчанию, используемое в DbModelBuilder:

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

Значение по умолчанию DecimalPropertyConventionв EF6 отображает decimalсвойства в decimal(18,2)столбцы.

Если вы хотите, чтобы отдельные свойства имели указанную точность, вы можете установить точность для свойства объекта в DbModelBuilder:

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

Или добавьте EntityTypeConfiguration<>для объекта, который указывает точность:

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
источник
1
Мое любимое решение. Прекрасно работает при использовании CodeFirst и миграций: EF ищет все свойства во всех классах, где используется «десятичное число», и генерирует миграцию для этих свойств. Большой!
хорошо
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"

После этого, если десятичная дробь обнуляется, я называю

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

метод (я называю это положением в массиве, это не идеально, я знаю, любая помощь будет высоко ценится)

и если это не обнуляемо, я называю

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

метод.

Имея DecimalPropertyConfiguration, я вызываю метод HasPrecision.

KinSlayerUY
источник
3
Спасибо за это. Это спасло меня от создания тысяч лямбда-выражений.
Шон
1
Это прекрасно работает, и очень чисто! Для EF 5 я изменил System.Data.Entity.ModelConfiguration.ModelBuilder на System.Data.Entity.DbModelBuilder
Колин
3
Я использую, MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });чтобы получить правильную перегрузку. кажется, работает до сих пор.
fscan
3
Я обернул это в библиотеку и упростил вызов из DbContext: github.com/richardlawley/EntityFrameworkAttributeConfig (также доступен через nuget)
Ричард
Ричард, мне нравится идея вашего проекта, но есть ли в нем что-то, что требует EF6? Я бы использовал его, если бы была EF5-совместимая версия, чтобы я мог использовать ее с моей версией ODP.NET.
Патрик Салапски
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());
}
kjbartel
источник
@MichaelEdenfield На самом деле нет, в EF6 такого нет. Поэтому я добавил два ответа, один и другой, на который вы ссылались. Это атрибут, который можно присвоить одному десятичному свойству, а не влиять на все десятичные свойства в модели.
kjbartel
Боже
1
Если вы собираетесь проверить границы 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. Например, numericтип PostgreSQL поддерживает до 131072 цифр точности.
NathanAldenSr
1
@NathanAldenSr Как я уже сказал, базы данных используют десятичную систему с фиксированной запятой ( 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 синтаксис был изменен, чтобы разрешить добавление точности и масштаба в одном выражении: modelBuilder.Entity <Product> (). Property (product => product.Price) .HasPrecision (6, 2);
полковник
2
Тем не менее, было бы неплохо иметь какое-то «значение по умолчанию», которое вы могли бы установить для всех десятичных дробей?
Дэйв Ван ден Эйнд
3
Я не думаю, что звонить base.OnModelCreating(modelBuilder);необходимо. Из метаданных DbContext в 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: Это хорошо, но как разработчик, я не должен заботиться об этом и всегда вызывать базу.
Дейв Ван ден Эйнде
@ Дэйв и @Matt: Был комментарий, что это было «ВАЖНО», чтобы позвонить базе. Это хорошая практика, но когда источник EF имеет пустую реализацию, вводить в заблуждение утверждение, что это важно, вводит в заблуждение. Это заставляет людей задуматься о том, что делает база. Мне было так любопытно, что ВАЖНО, я декомпилировал в ef5.0 для проверки. Здесь пусто. Так что просто хорошая привычка.
Фил Соади
30

В Entity Framework версии 6 (Alpha, rc1) есть нечто, называемое пользовательскими соглашениями . Чтобы установить десятичную точность:

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

Ссылка:

mxasim
источник
22
[Column(TypeName = "decimal(18,2)")]

это будет работать с первыми миграциями кода EF Core, как описано здесь .

Elnoor
источник
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. Устаревшая неосновная версия не поддерживает указание точности / масштаба через атрибут Column и ничего не делает (по умолчанию 18,2), если вы используете атрибут DataType. Чтобы заставить его работать через Attribute в EF 6.x, вам нужно реализовать собственное расширение для ModelBuilder.
Крис Москини
1
@ChrisMoschini, я изменил свой ответ, упомянув EF Core. Спасибо
Elnoor
14

эта строка кода может быть более простым способом сделать то же самое:

 public class ProductConfiguration : EntityTypeConfiguration<Product>
    {
        public ProductConfiguration()
        {
            this.Property(m => m.Price).HasPrecision(10, 2);
        }
    }
armadillo.mx
источник
9

- ДЛЯ EF CORE - с использованием 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

sofsntp
источник
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);
    });
user3332875
источник
Этот ответ, кажется, является обновлением до другого ответа, который определяет атрибут, вы должны отредактировать его в этом ответе
Рис Бевилаква
3

Вы всегда можете сказать 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);
}

Это относится только к FY Code First EF и относится ко всем десятичным типам, отображаемым в БД.

Геккон ИТ
источник
Это не работает, пока не Remove<DecimalPropertyConvention>();наступит раньше Add(new DecimalPropertyConvention(18, 4));. Я думаю, что это странно, что не просто автоматически переопределяется.
Майк де Клерк
2

С помощью

System.ComponentModel.DataAnnotations;

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

[DataType("decimal(18,5)")]
VinnyG
источник
1
это самая простая реализация для удобства чтения и простоты. ИМХО
ранцемс
11
Согласно msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx , этот ответ фактически неверен. «Не путайте атрибут TypeName столбца с DataType DataAnnotation. DataType - это аннотация, используемая для пользовательского интерфейса, которая игнорируется Code First».
speckledcarp
2
@ransems Я тоже так думал, пока я только что проверил это и, как было сказано выше, это не работает для CodeFirst и не переносится в базу данных
RoLYroLLs
1

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

Jaider
источник
Это здорово и все, но как это относится к Code-First?
Дэйв Ван ден Эйнд
Это полезно, но я не могу указать атрибут [Precision] для десятичного числа. Поэтому я использовал решение, предоставленное @KinSlayerUY.
Колин
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);
            }
        }
    }
Mark007
источник
0

@ 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;
            }
        }
    }
Eniola
источник
Я просто понял, что не имею дело с ComplexTypes таким подходом. Буду пересматривать это позже.
Эниола
Однако решение, предложенное Брайаном , простое, элегантное и работает. Я не буду делать категорических заявлений о производительности, но использование уже отраженного PropertyInfo, а не поиск вашей, должно привести к лучшей производительности на очень больших моделях (порядка 200 и выше).
Эниола