سؤال

أنا أجرب هذا النهج الأول من الكود ، لكنني اكتشف الآن أن خاصية من النوع System.Simal يتم تعيينها إلى عمود SQL من النوع العشري (18 ، 0).

كيف يمكنني تعيين دقة عمود قاعدة البيانات؟

هل كانت مفيدة؟

المحلول

الجواب من ديف فان دن إييندي هو الآن قديم. هناك تغييران مهمان ، من EF 4.1 فصاعدًا ، فئة ModelBuilder أصبحت الآن DBModelBuilder وهناك الآن طريقة dcimalpropertyconfiguration.

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

عندما تكون الدقة هي العدد الإجمالي للأرقام التي سيتم تخزينها DB ، بغض النظر عن المكان الذي تسقط فيه النقطة العشرية والمقياس هو عدد الأماكن العشرية التي سيتم تخزينها.

لذلك ليست هناك حاجة للتكرار من خلال الخصائص كما هو موضح ولكن يمكن استدعاء فقط

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

نصائح أخرى

إذا كنت تريد ضبط الدقة للجميع 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);
    }
}

لقد قضيت وقتًا ممتعًا في إنشاء سمة مخصصة لهذا:

[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" Lambda Expression

بعد ذلك ، إذا كان العشري قابلاً للبطولة ، فأنا أسمي

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

الطريقة (أسمي هذا من خلال الموقف في المصفوفة ، فهي ليست مثالية أعرفها ، أي مساعدة ستكون موضع تقدير كبير)

وإذا لم يكن قابلاً للبطولة ، فأنا أسمي

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

طريقة.

امتلاك عملية تكوين DecimalPropertyConcision.

على ما يبدو ، يمكنك تجاوز طريقة 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);
    }

من الممارسات الجيدة أن تسميها الطريقة الأساسية عند تجاوز طريقة ما ، على الرغم من أن تطبيق الأساس لا يفعل شيئًا.

تحديث: هذه المقالة كان أيضا مفيدة جدا.

باستخدام DecimalPrecisonAttribute من 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());
}

إطار الكيان VER 6 (Alpha ، RC1) لديه شيء يسمى اتفاقيات مخصصة. لتعيين الدقة العشرية:

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

المرجعي:

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

سيعمل هذا مع ترحيل الكود الأول كما هو موضح هنا.

يمكن أن يكون خط الرمز هذا وسيلة أبسط لإلغاء نفس:

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

- لـ 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

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

يمكنك دائمًا إخبار EF بالقيام بذلك مع الاتفاقيات في فئة السياق في وظيفة 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);
}

ينطبق هذا فقط على الكود الأول EF FYI وينطبق على جميع الأنواع العشرية المعينة على DB.

استخدام

System.ComponentModel.DataAnnotations;

يمكنك ببساطة وضع هذه السمة في النموذج الخاص بك:

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

يمكنك العثور على مزيد من المعلومات حول MSDN - Facet من نموذج بيانات الكيان.http://msdn.microsoft.com/en-us/library/ee382834.aspxالموصى بها كاملة.

عملت السمة المخصصة لـ Kinslayeruy بشكل جيد بالنسبة لي ، لكنني واجهت مشاكل مع ComplexTypes. تم تعيينها ككيانات في رمز السمة ، لذا لا يمكن تعيينها بعد ذلك كمعقدة.

لذلك قمت بتوسيع الكود للسماح بذلك:

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 ، قمت بتغيير معايير اختيار النوع لركوب خصائص DBSET <> من DBContext. أعتقد أن هذا أكثر أمانًا لأن هناك أوقاتًا يكون فيها فصولًا في مساحة الاسم المحددة لا ينبغي أن تكون جزءًا من تعريف النموذج أو أنها ليست كيانات. أو يمكن أن تتواجد كياناتك في مساحات أسماء منفصلة أو تجميعات منفصلة وسحبها معًا في سياق مرة واحدة.

أيضًا ، على الرغم من أنه من غير المحتمل ، لا أعتقد أنه من الآمن الاعتماد على طلب تعريفات الطريقة ، لذلك من الأفضل سحبها بواسطة قائمة المعلمات. (.

لاحظ أن 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;
            }
        }
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top