Vin*_*zon 4 entity-framework code-first ef-code-first
我有 DateTime 的并发令牌问题。这是重现问题的简单方法。拥有一个实体:
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
[ConcurrencyCheck]
public DateTime LastModified { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
一个简单的 DbContext:
public class MyContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
以及以下代码:
Employee orig;
// Create a row (insert)
using (var context = new MyContext())
{
orig = new Employee
{
Name = "Mike",
LastModified = DateTime.Now
};
context.Employees.Add(orig);
context.SaveChanges();
}
// Update the row, passing the right concurrency token
using (var context = new MyContext())
{
var clone = new Employee
{
EmployeeID = orig.EmployeeID,
Name = "Suzanne",
// Pass the concurrency token here
LastModified = orig.LastModified
};
context.Employees.Attach(clone);
// Mark the entity as modified to force an update
context.Entry(clone).State = EntityState.Modified;
// Boom! Currency exception!
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
基本上,我创建一个员工,然后更新它。砰! 我查看在 SQL (Profiling) 上生成的更新语句:
exec sp_executesql N'update [dbo].[Employees]
set [Name] = @0, [LastModified] = @1
where (([EmployeeID] = @2) and ([LastModified] = @3))
',N'@0 nvarchar(max) ,@1 datetime2(7),@2 int,@3 datetime2(7)',@0=N'Suzanne',@1='2012-02-21
12:06:30.0141536',@2=0,@3='2012-02-21 12:06:30.0141536'
Run Code Online (Sandbox Code Playgroud)
该语句对我来说似乎是合理的,但它失败了,即将零行修改为好像 ([LastModified] = @3) 失败。
我怀疑存在“精度问题”,即与存储的位数不匹配的位数。.NET 和 SQL 中的 DateTime 表示形式是否不匹配?
我试过在我的 Poco 类中使用 System.Data.SqlTypes.SqlDateTime 而不是 DateTime,希望这能带来正确的精度,但我无法映射它,EF 总是有未映射的属性。
解决方案?
我发现了问题!实际上,这里有两个问题:技术问题和语义问题。
技术问题是 EF,无论出于何种原因,将 System.DateTime 作为 datetime(2) SQL 类型发送到 SQL。默认情况下,它确实将 System.DateTime 映射为日期时间。尽管强制 SQL 类型为 datetime(2),但我实际上并没有成功让 EF 使用 datetime(2) 创建数据库。但是如果你事后改变它,它就解决了问题。所以这个问题实际上是一个精度问题。
语义问题是,如果您考虑一下,整个就没有意义。并发令牌是您需要传递给 SQL 以证明您是最后一个读取表的对象。但是因此每次更新行时都需要更新并发令牌。一个排除另一个:如果您尝试将 LastModified 更新为 DateTime.Now,您将遇到并发异常,因为并发令牌不是存储在行中的令牌!
因此,尽管找到了技术问题的解决方案,但整个方案没有任何意义。
... 除非!您找到了一种无需使用 EF 即可更新 LastModified 列的方法。例如,您可以有一个触发器。通常你不会想去那里。
| 归档时间: |
|
| 查看次数: |
2179 次 |
| 最近记录: |