Độ chính xác thập phân và thang đo trong Mã EF Đầu tiên


230

Tôi đang thử nghiệm phương pháp tiếp cận mã đầu tiên này, nhưng bây giờ tôi phát hiện ra rằng một thuộc tính thuộc loại System.Decimal được ánh xạ tới cột sql có kiểu thập phân (18, 0).

Làm cách nào để đặt độ chính xác của cột cơ sở dữ liệu?


11
một cách là sử dụng [Column(TypeName = "decimal(18,4)")]thuộc tính cho các thuộc tính thập phân của bạn
S.Serpooshan

[Cột (TypeName = "thập phân (18,4)")] hoạt động rất tốt !!!
Brian Rice

Câu trả lời:


257

Câu trả lời từ Dave Van den Eynde hiện đã hết hạn. Có 2 thay đổi quan trọng, từ EF 4.1 trở đi, lớp ModelBuilder hiện là DbModelBuilder và giờ đây có Phương thức DecimalPropertyConfiguration.HasPrecision có chữ ký:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

trong đó độ chính xác là tổng số chữ số mà db sẽ lưu trữ, bất kể điểm thập phân rơi ở đâu và tỷ lệ là số vị trí thập phân mà nó sẽ lưu trữ.

Do đó, không cần phải lặp qua các thuộc tính như được hiển thị nhưng chỉ có thể được gọi từ

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

Đối với bất kỳ ai đang gặp sự cố với DbModelBuilder, hãy thửSystem.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
Lloyd Powell

1
Tôi nhận thấy bạn không bao giờ gọi base.OnModelCreating(modelBuilder);. Đó có phải là cố ý hay chỉ là nạn nhân của việc gõ mã trực tuyến thay vì trong IDE?
BenSwayne

1
@BenSwayne cảm ơn vì vị trí này, đây là thiếu sót của tôi, không phải bất cứ điều gì có chủ ý. Tôi sẽ chỉnh sửa câu trả lời.
AlexC

26
2 đối số cho HasPrecision (độ chính xác, tỷ lệ) được ghi lại kém. độ chính xác là tổng số chữ số mà nó sẽ lưu trữ, bất kể điểm thập phân rơi ở đâu. quy mô là số vị trí thập phân nó sẽ lưu trữ.
Chris Moschini

1
Có cấu hình EF để đặt cấu hình cho tất cả các thuộc tính thập phân trên tất cả các thực thể ở một nơi không? Chúng tôi thường sử dụng (19,4). Thật tuyệt khi áp dụng điều này tự động cho tất cả các thuộc tính thập phân, vì vậy chúng ta không thể quên đặt độ chính xác của thuộc tính và bỏ lỡ độ chính xác dự đoán trong các phép tính.
Mike de Klerk

89

Nếu bạn muốn đặt độ chính xác cho tất cả decimalstrong EF6, bạn có thể thay thế DecimalPropertyConventionquy ước mặc định được sử dụng trong DbModelBuilder:

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

Mặc định DecimalPropertyConventiontrong EF6 ánh xạ decimalcác thuộc tính vào decimal(18,2)các cột.

Nếu bạn chỉ muốn các thuộc tính riêng lẻ có độ chính xác được chỉ định thì bạn có thể đặt độ chính xác cho thuộc tính của thực thể trên DbModelBuilder:

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

Hoặc, thêm một EntityTypeConfiguration<>thực thể xác định độ chính xác:

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
Giải pháp yêu thích của tôi. Hoạt động hoàn hảo khi sử dụng CodeFirst và di chuyển: EF tìm kiếm tất cả các thuộc tính trong tất cả các lớp trong đó "thập phân" được sử dụng và tạo di chuyển cho các thuộc tính này. Tuyệt quá!
okieh

75

Tôi đã có một thời gian tuyệt vời để tạo Thuộc tính tùy chỉnh cho việc này:

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

}

sử dụng nó như thế này

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

và điều kỳ diệu xảy ra khi tạo mô hình với một số phản chiếu

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

phần đầu tiên là để có được tất cả các lớp trong mô hình (thuộc tính tùy chỉnh của tôi được xác định trong cụm đó vì vậy tôi đã sử dụng nó để lấy cụm với mô hình)

foreach thứ hai có được tất cả các thuộc tính trong lớp đó với thuộc tính tùy chỉnh và chính thuộc tính đó để tôi có thể có được dữ liệu chính xác và tỷ lệ

sau đó tôi phải gọi

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

vì vậy tôi gọi modelBuilder.Entity () bằng cách phản chiếu và lưu trữ nó trong biến entityConfig sau đó tôi xây dựng biểu thức lambda "c => c.PROPERTY_NAME"

Sau đó, nếu số thập phân là null, tôi gọi

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

phương pháp (tôi gọi điều này theo vị trí trong mảng, nó không lý tưởng tôi biết, bất kỳ trợ giúp sẽ được đánh giá cao)

và nếu nó không rỗng, tôi gọi

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

phương pháp.

Có DecimalPropertyConfiguration tôi gọi phương thức HasPrecision.


3
Cảm ơn vì điều đó. Nó đã cứu tôi khỏi việc tạo ra hàng ngàn biểu thức lambda.
Sean

1
Điều này làm việc tuyệt vời, và là siêu sạch! Đối với EF 5, tôi đã thay đổi System.Data.Entity.ModelConfiguration.ModelBuilder thành System.Data.Entity.DbModelBuilder
Colin

3
tôi sử dụng MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });để có được quá tải chính xác. dường như làm việc cho đến nay.
fscan

3
Tôi đã gói nó vào một thư viện và giúp gọi từ DbContext dễ dàng hơn: github.com/richardlawley/EntityFrameworkAttributionConfig (cũng có sẵn qua nuget)
Richard

Richard, tôi thích ý tưởng về dự án của bạn nhưng có bất cứ điều gì về nó đòi hỏi phải có EF6 không? Tôi sẽ sử dụng nó nếu có phiên bản tương thích với EF5, để tôi có thể sử dụng nó với phiên bản ODP.NET của mình.
Patrick Szalapski

50

Sử dụng DecimalPrecisonAttributetừ KinSlayerUY, trong EF6, bạn có thể tạo một quy ước sẽ xử lý các thuộc tính riêng lẻ có thuộc tính (trái ngược với cài đặtDecimalPropertyConvention giống như trong câu trả lời này sẽ ảnh hưởng đến tất cả các thuộc tính thập phân).

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

Sau đó, trong của bạn DbContext:

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

@MichaelEdenfield Trên thực tế không có một trong số này trong EF6. Do đó tại sao tôi thêm hai câu trả lời, câu trả lời này và câu trả lời khác mà bạn đề cập. Đây là một thuộc tính bạn có thể đặt trên một thuộc tính thập phân duy nhất thay vì ảnh hưởng đến tất cả các thuộc tính thập phân trong mô hình.
kjbartel

xấu của tôi, đã không nhận thấy bạn đã viết cả hai: \
Michael Edenfield

1
Nếu bạn định kiểm tra giới hạn Precision, thì tôi khuyên bạn nên đặt giới hạn trên thành 28 (vì vậy > 28trong điều kiện của bạn). Theo tài liệu MSDN, System.Decimalchỉ có thể biểu thị tối đa 28-29 chữ số chính xác ( msdn.microsoft.com/en-us/l Library / 44x0z75.aspx ). Ngoài ra, thuộc tính khai báo Scalebyte, điều đó có nghĩa là điều kiện tiên quyết của bạn attribute.Scale < 0là không cần thiết.
NathanAldenSr

2
@kjbartel Đúng là một số nhà cung cấp cơ sở dữ liệu hỗ trợ các phần lớn hơn 28; tuy nhiên, theo MSDN, System.Decimalthì không. Do đó, không có ý nghĩa gì khi đặt điều kiện tiên quyết trên cho bất cứ điều gì lớn hơn 28; System.DecimalKhông thể đại diện cho số lượng lớn, rõ ràng. Ngoài ra, hãy lưu ý rằng thuộc tính này hữu ích cho các nhà cung cấp dữ liệu ngoài SQL Server. Ví dụ, numericloại của PostgreQuery hỗ trợ độ chính xác lên tới 131072 chữ số.
NathanAldenSr

1
@NathanAldenSr Giống như tôi đã nói, cơ sở dữ liệu sử dụng số thập phân điểm cố định ( msdn ) trong khi System.Decimal là dấu phẩy động . Chúng hoàn toàn khác nhau. Ví dụ: có một decimal(38,9)cột sẽ giữ hạnh phúc System.Decimal.MaxValuenhưng một decimal(28,9)cột thì không. Không có lý do gì để giới hạn độ chính xác chỉ còn 28.
kjbartel

47

Rõ ràng, bạn có thể ghi đè phương thức DbContext.OnModelCreating () và định cấu hình độ chính xác như sau:

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

Nhưng đây là mã khá tẻ nhạt khi bạn phải làm điều đó với tất cả các thuộc tính liên quan đến giá của bạn, vì vậy tôi đã đưa ra điều này:

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

Đó là một thực hành tốt mà bạn gọi phương thức cơ sở khi bạn ghi đè một phương thức, mặc dù việc triển khai cơ sở không làm gì cả.

Cập nhật: Bài viết này cũng rất hữu ích.


10
Cảm ơn, điều này chỉ cho tôi đi đúng hướng. Trong CTP5, cú pháp đã thay đổi để cho phép thêm Độ chính xác và Tỷ lệ trong cùng một câu lệnh: modelBuilder.Entity <Product> (). Property (sản phẩm => sản phẩm.price) .HasPrecision (6, 2);
Đại tá

2
Tuy nhiên, sẽ thật tuyệt nếu có một số loại "mặc định" mà bạn có thể đặt cho tất cả các số thập phân?
Dave Van den Eynde

3
Tôi không nghĩ rằng việc gọi base.OnModelCreating(modelBuilder);là cần thiết. Từ siêu dữ liệu DbContext trong 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 Jenkins

@Matt: Thật tuyệt, nhưng với tư cách là người triển khai, tôi không nên quan tâm đến vấn đề này và luôn gọi cho cơ sở.
Dave Van den Eynde

@ Dave và @Matt: Có một nhận xét đó là "QUAN TRỌNG" để gọi cơ sở. Đó là một thực tiễn tốt, nhưng khi nguồn EF có một triển khai trống, thì việc tuyên bố nó là quan trọng. Điều đó khiến mọi người tự hỏi những gì các cơ sở làm. Tôi đã rất tò mò về những gì QUAN TRỌNG tôi đã dịch ngược sang ef5.0 để kiểm tra. Không co gi ở đo. Vì vậy, chỉ là một thói quen tốt.
phil soady

30

Entity Framework Ver 6 (Alpha, rc1) có một thứ gọi là Quy ước tùy chỉnh . Để đặt độ chính xác thập phân:

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

Tài liệu tham khảo:


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

điều này sẽ hoạt động với các lần di chuyển đầu tiên của mã EF Core như được mô tả ở đây .


1
Nếu bạn chỉ cần thêm nó vào mô hình của mình, bạn có thể nhận đượcThe store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
Savage

@Savage có vẻ như đó là sự cố với nhà cung cấp cơ sở dữ liệu của bạn hoặc phiên bản của cơ sở dữ liệu
Elnoor

@Elnoor Savage là chính xác, điều này sẽ gây ra lỗi trong EF Migration 6.x. Phiên bản kế thừa, không phải Core không hỗ trợ chỉ định độ chính xác / tỷ lệ thông qua thuộc tính Cột và không làm gì (mặc định là 18,2) nếu bạn sử dụng thuộc tính DataType. Để làm cho nó hoạt động thông qua Thuộc tính trong EF 6.x, bạn sẽ cần triển khai tiện ích mở rộng của riêng mình cho ModelBuilder.
Chris Moschini

1
@ChrisMoschini, tôi đã thay đổi câu trả lời của mình khi đề cập đến EF Core. Cảm ơn
Elnoor

14

dòng mã này có thể là một cách đơn giản hơn để hoàn thành tương tự:

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

9

- CHO EF CORE - với việc sử dụng System.ComponentModel.DataAnnotations;

sử dụng [Column( TypeName = "decimal( độ chính xác , tỷ lệ )")]

Chính xác = Tổng số ký tự được sử dụng

Tỷ lệ = Tổng số sau dấu chấm. (dễ bị nhầm lẫn)

Ví dụ :

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

Thêm chi tiết tại đây: https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-types


3

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

Câu trả lời này dường như là một bản nâng cấp cho câu trả lời khác xác định thuộc tính, bạn nên chỉnh sửa câu trả lời này thành câu trả lời đó
Rhys Bevilaqua

3

Bạn luôn có thể yêu cầu EF thực hiện điều này với các quy ước trong lớp Ngữ cảnh trong hàm OnModelCreating như sau:

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

Điều này chỉ áp dụng cho Code First EF fyi và áp dụng cho tất cả các loại thập phân được ánh xạ tới db.


Nó đã không hoạt động cho đến khi Remove<DecimalPropertyConvention>();đến trước Add(new DecimalPropertyConvention(18, 4));. Tôi nghĩ thật lạ khi nó không bị ghi đè tự động.
Mike de Klerk

2

Sử dụng

System.ComponentModel.DataAnnotations;

Bạn chỉ có thể đặt thuộc tính đó trong mô hình của mình:

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

1
đây là cách thực hiện dễ dàng nhất để dễ đọc và đơn giản. IMHO
ransems

11
Mỗi msdn.microsoft.com/en-us/l Library / jj591583 (v = vs.113) .aspx , câu trả lời này thực tế không chính xác. "Đừng nhầm lẫn thuộc tính TypeName của Cột với Chú thích dữ liệu DataType. Kiểu dữ liệu là một chú thích được sử dụng cho giao diện người dùng và bị Mã đầu tiên bỏ qua."
speckledcarp

2
@ransems Tôi cũng nghĩ vậy, cho đến khi tôi mới thử nó và như đã nói ở trên, điều này không hoạt động với CodeFirst và không di chuyển đến cơ sở dữ liệu
RoLYroLLs

1

Bạn có thể tìm thấy thêm thông tin về MSDN - khía cạnh của Mô hình dữ liệu thực thể. http://msdn.microsoft.com/en-us/l Library / ee382834.aspx Được đề xuất đầy đủ.


Điều đó thật tuyệt vời và tất cả, nhưng điều đó liên quan đến Code-First như thế nào?
Dave Van den Eynde

Nó rất hữu ích nhưng tôi không thể chỉ định thuộc tính [Chính xác] cho số thập phân. Vì vậy, tôi đã sử dụng giải pháp được cung cấp bởi @KinSlayerUY.
Colin

1

Thực tế cho EntityFrameworkCore 3.1.3:

Một số giải pháp trong 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

Thuộc tính tùy chỉnh của KinSlayerUY hoạt động tốt đối với tôi nhưng tôi gặp vấn đề với ComplexTypes. Chúng được ánh xạ như các thực thể trong mã thuộc tính, do đó không thể ánh xạ thành ComplexType.

Do đó tôi đã mở rộng mã để cho phép điều này:

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, tôi đã thay đổi tiêu chí lựa chọn loại để sử dụng các thuộc tính Dbset <> của DbContext. Tôi nghĩ rằng điều này an toàn hơn vì có những lúc bạn có các lớp trong không gian tên đã cho mà không phải là một phần của định nghĩa mô hình hoặc chúng là nhưng không phải là các thực thể. Hoặc các thực thể của bạn có thể cư trú trong các không gian tên riêng biệt hoặc các cụm riêng biệt và được kéo lại với nhau thành một bối cảnh.

Ngoài ra, mặc dù không có khả năng, tôi không nghĩ sẽ an toàn khi dựa vào thứ tự các định nghĩa phương thức, vì vậy tốt hơn hết là lấy chúng ra bằng danh sách Thông số. (.GetTypeMethods () là một phương thức mở rộng mà tôi đã xây dựng để làm việc với mô hình TypeInfo mới và có thể làm phẳng hệ thống phân cấp lớp khi tìm kiếm các phương thức).

Xin lưu ý rằng các đại biểu OnModelCreating cho phương thức này:

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

Tôi chỉ nhận ra rằng tôi đã không đối phó với ComplexTypes bằng cách tiếp cận này. Sẽ sửa lại sau.
Eniola

Tuy nhiên, giải pháp được đề xuất bởi Brian là đơn giản, thanh lịch và hoạt động. Tôi sẽ không đưa ra bất kỳ tuyên bố phân loại nào về hiệu suất nhưng việc phản ánh PropertyInfo đã được phản ánh thay vì săn lùng của bạn sẽ mang lại hiệu suất tốt hơn trên các mô hình rất lớn (theo thứ tự 200 trở lên).
Eniola
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.