解决 Entity Framework 6.0 decimal 类型精度问题
Ø 前言
本文主要解决 EF 中对于 MSSQL 数据库的 decimal 类型经度问题,经实验该问题仅在 CodeFirst 模式的情况下发生,话不多说直接看代码。
1. 假设我们有一张 Customer 数据表,主要探究:Longitude、Latitude、LonLatSum 这三个字段。
1) 结构如下:
CREATE 的数据)
1) C# 代码如下:
using (MyTestingEntities context = new MyTestingEntities())
{
Customer entity = context.Customers.Attach(new Customer() { Id = 1 });
entity.Longitude = 123.1256789f; //123.125679
entity.Latitude = 456.1295678d; //456.1295678
entity.LonLatSum = (decimal)(entity.Longitude + entity.Latitude); //579.255246816113M
context.Configuration.ValidateOnSaveEnabled = false;
result = context.SaveChanges() > 0;
}
2) 生成SQL:
exec 位小数。
2. Latitude:float 类型(对应 C# 中的 double 类型),保留了7位小数。
3. LonLatSum:decimal 类型(对应 C# 中的 decimal 类型),也保留了7位小数。
4. OK 这是正常的。
3. 然后,我们再使用 Code Frirst 的方式对数据更新(更新 Id 为2的数据)
1) C# 代码如下:
using (MyTestingContext context = new MyTestingContext())
{
Customer entity = context.Customer.Attach(new Customer() { Id = 2 });
entity.Longitude = 123.1256789f; //123.125679
entity.Latitude = 456.1295678d; //456.1295678
entity.LonLatSum = (decimal)(entity.Longitude + entity.Latitude); //579.255246816113M
result = context.SaveChanges() > 0;
}
return result;
2) 生成SQL:
exec )和小数位数(2位)的方式生成了,结果 SQL 的类型声明是这样:decimal(18,2)。
3) 搞清楚了问题,下面我们就来解决这个问题吧。
5. 解决问题
1) 创建一个 DecimalPrecisionAttribute 特性类
/// <summary>
/// 用于指定 decimal 类型的精确度与小数保留位数。
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class DecimalPrecisionAttribute : Attribute
{
private byte _precision;
/// <summary>
/// 精确度。
/// </summary>
public byte Precision
{
get { return _precision; }
set { _precision = value; }
}
private byte _scale;
/// <summary>
/// 小数保留位数。
/// </summary>
public byte Scale
{
get { return _scale; }
set { _scale = value; }
}
/// <summary>
/// 根据指定的精确度与小数保留位数,初始化 DecimalPrecisionAttribute 的实例。
/// </summary>
/// <param name="precision">精确度。</param>
/// <param name="scale">小数保留位数。</param>
public DecimalPrecisionAttribute(byte precision, byte scale)
{
this.Precision = precision;
this.Scale = scale;
}
}
2) 再创建一个 DecimalPrecisionAttributeConvention 类(表示 DecimalPrecisionAttribute 的一种约定)
1. 该类继承于 System.Data.Entity.ModelConfiguration.Conventions.PrimitivePropertyAttributeConfigurationConvention 类。
2. 并实现 Apply 抽象方法,通俗点说:该方法在“生成 SQL”时被调用,对于打了 DecimalPrecisionAttribute 标记的实体属性,精度将根据 configuration.HasPrecision() 方法中的设置去生成。
/// <summary>
/// 表示 DecimalPrecisionAttribute 的一种约定。
/// </summary>
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);
}
}
3) 在数据上下文的 OnModelCreating() 方法将该 DecimalPrecisionAttributeConvention(约定)加入数据约定集合中。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}
4) 最后一步,将需要设置小数位数的属性打上 DecimalPrecision 标记,例如:
[DecimalPrecision(18, 7)]
public decimal LonLatSum { get; set; }
5) 好了之后再次运行代码,生成 SQL 如下:
exec sp_executesql N'UPDATE [dbo].[Customer]
SET [Longitude] = @0, [Latitude] = @1, [LonLatSum] = @2
WHERE ([Id] = @3)
',N'@0 real,@1 float,@2 decimal(18,7),@3 int',@0=123.12567901611328,@1=456.12956780000002,@2=579.2552468,@3=2
6) 结果如下:
7) OK,这样就与 DB First 生成的 SQL 没什么区别了。
最新文章
- HDU 1232 并查集/dfs
- 在Salesforce中通过 Debug Log 方式 跟踪逻辑流程
- dyld: Library not loaded: /System/Library/Frameworks/UserNotifications.framework/UserNotifications解决办法
- UI基础:UICollectionView
- python字符串连接的三种方法及其效率、适用场景详解
- Windows Phone 8初学者开发—第5部分:布局和事件基础
- python--同步锁/递归锁/协程
- What&#39;s the meaning of unqualified-id?
- 一对一关联模型,HAS_ONE
- db2 varchar字段类型太大问题
- Tensorflow的验证码识别
- solr6.2单机版安装
- What-is-DevOps
- css常见问题一
- Linux上查看文件大小的用法(转载)
- 注册表彻底卸载sql
- Linux入门基础(七):Linux软件管理基础
- angular 神坑 ,回调函数无法被监视
- Boatloader的工作流程
- 用Nginx反向代理Node.js