我需要翻译的内容是关于IT技术的,涉及并发令牌和DateTime问题。以下是重现该问题的简单方法。首先有一个实体:
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
[ConcurrencyCheck]
public DateTime LastModified { get; set; }
}
一个简单的DbContext:
public class MyContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
以下是代码:
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();
}
基本上,我创建一个员工,然后更新它。瞧!我查看在 SQL(分析)上生成的更新语句:
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'
该语句在我看来似乎正确,但是它失败了,也就是说,它会修改零行,就好像([LastModified] = @3) 失败了。
我怀疑存在“精度问题”,即数字的位数与存储的数字不匹配。这可能是.NET和SQL之间DateTime表示方式不匹配导致的吗?
我尝试在我的Poco类中使用System.Data.SqlTypes.SqlDateTime代替DateTime,希望它能够携带正确的精度,但我无法进行映射,EF总是将该属性保持未映射状态。
解决方案?
LastModified
属性具有ConcurrencyCheck
特性,如果DateTime
具有比SQL Server数据类型更高的精度,则应在SaveChanges
之后将其截断。 如果DateTime
精度较低,则应该准确地存储该值。 无论哪种方式,在SaveChanges
之后,LastModified
属性应与数据库中存储的内容完全匹配。您可以通过检索没有EF的日期来检查存储了什么。 - user743382datetime
(而不是datetime2
),但 EF 仍然以某种原因将参数发送到更新查询中作为datetime2
。你最终是如何解决这个问题的? - sinelawProviderManifestToken
设置为2005
解决了我的问题。我正在使用 Code First,所以解决方法涉及创建自己的DbModelBuilder
。请参见 这个答案。 - sinelaw