[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);
}
}
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
this.Property(m => m.Price).HasPrecision(10, 2);
}
}
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; }
}
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);
}
15 回答
在EF6中
Dave Van den Eynde的答案现已过时 . 有两个重要的变化,从EF 4.1开始,ModelBuilder类现在是DbModelBuilder,现在有一个DecimalPropertyConfiguration.HasPrecision方法,其签名为:
其中precision是db将存储的总位数,无论小数点落在何处,scale是它将存储的小数位数 .
因此,不需要迭代所示的属性,但可以从中调用
如果要为EF6中的所有
decimals
设置精度,可以替换DbModelBuilder
中使用的默认DecimalPropertyConvention
约定:EF6中的默认
DecimalPropertyConvention
将decimal
属性映射到decimal(18,2)
列 .如果您只希望单个属性具有指定的精度,则可以在
DbModelBuilder
上设置实体属性的精度:或者,为指定精度的实体添加
EntityTypeConfiguration<>
:我很高兴为此创建自定义属性:
像这样使用它
并且通过一些反思在模型创造中发生了魔力
第一部分是获取模型中的所有类(我的自定义属性在该程序集中定义,所以我用它来获取模型的程序集)
第二个foreach使用自定义属性和属性本身获取该类中的所有属性,以便我可以获得精度和比例数据
之后我必须打电话
所以我通过反射调用modelBuilder.Entity()并将其存储在entityConfig变量中然后构建“c => c.PROPERTY_NAME”lambda表达式
之后,如果小数可以为空,我会调用
方法(我通过数组中的位置调用它,它不是理想我知道,任何帮助将不胜感激)
如果它不可空,我会打电话给
方法 .
使用DecimalPropertyConfiguration我调用HasPrecision方法 .
显然,您可以覆盖DbContext.OnModelCreating()方法并配置如下精度:
但是当你必须使用所有与价格相关的属性时,这是相当繁琐的代码,所以我想出了这个:
在覆盖方法时调用基本方法是一种很好的做法,即使基本实现什么也不做 .
更新:This article也非常有帮助 .
使用来自KinSlayerUY的
DecimalPrecisonAttribute
,在EF6中,您可以创建一个约定来处理具有该属性的各个属性(而不是在this answer中设置DecimalPropertyConvention
,这将影响所有小数属性) .然后在你的
DbContext
:实体框架Ver 6(Alpha,rc1)有一个名为 Custom Conventions 的东西 . 要设置小数精度:
参考:
http://entityframework.codeplex.com/wikipage?title=Custom%20Conventions
http://weblogs.asp.net/scottgu/archive/2012/12/11/entity-framework-6-alpha2-now-available.aspx
这段代码可能是一种更简单的方法来完成相同的事情:
这将适用于代码首次迁移,如here所述 .
- FOR EF CORE - 与 using System.ComponentModel.DataAnnotations;
使用
[Column
(TypeName
= "decimal
( precision , scale )")]
精度=使用的总字符数
比例=点后的总数 . (容易混淆)
Example :
更多细节:https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-types
您总是可以告诉EF使用OnModelCreating函数中的Context类中的约定来执行此操作,如下所示:
这仅适用于Code First EF fyi,适用于映射到db的所有十进制类型 .
您可以在MSDN上找到更多信息 - 实体数据模型的方面 . http://msdn.microsoft.com/en-us/library/ee382834.aspx完全推荐 .
运用
您可以简单地将该属性放在模型中:
KinSlayerUY的自定义属性对我很有用,但我遇到了ComplexTypes的问题 . 它们被映射为属性代码中的实体,因此无法将其映射为ComplexType .
因此我扩展了代码以允许这样做:
@ Mark007,我已经将类型选择标准更改为乘坐DbContext的DbSet <>属性 . 我认为这更安全,因为有时你在给定的命名空间中有不应该是模型定义的一部分的类,或者它们不是实体 . 或者您的实体可以驻留在单独的命名空间或单独的程序集中,并将它们组合到一次Context中 .
此外,即使不太可能,我认为依靠方法定义的排序是不安全的,所以最好通过参数列表将它们拉出来 . (.GetTypeMethods()是我为使用新的TypeInfo范例而构建的扩展方法,可以在查找时展平类层次结构方法) .
请注意OnModelCreating委托给此方法: