【发布时间】:2015-11-22 14:05:54
【问题描述】:
假设我们在 SQL server 中有“EfTest”数据库和下表:
create table Test
(
Id INT NOT NULL IDENTITY(1,1),
TS DATETIME NOT NULL
PRIMARY KEY (TS, Id)
)
我们想用 EF(在我的例子中是 EF 5)在那里添加东西。我们在示例项目中从数据库创建 edmx 文件并编写以下代码:
static void Main(string[] args)
{
var ctx = new EFTestEntities();
var t = new Test();
t.TS = DateTime.Now;
ctx.Tests.Add(t);
ctx.SaveChanges();
}
我们运行它,它在ctx.SaveChanges() 行上以DbUpdateConcurrencyException 失败,说:
存储更新、插入或删除语句影响了意外 行数 (0)。实体可能已被修改或删除 实体已加载。刷新 ObjectStateManager 条目。
显然,那里没有发生并发。 SQL Server 探查器报告以下查询由 EF 运行:
exec sp_executesql N'insert [dbo].[Test]([TS])
values (@0)
select [Id]
from [dbo].[Test]
where @@ROWCOUNT > 0 and [Id] = scope_identity() and [TS] = @0',N'@0 datetime2(7)',@0='2015-08-27 18:29:45.1025442'
问题出在这里:@0 datetime2(7),@0='2015-08-27 18:29:45.1025442'。 DATETIME2 比 DATETIME 和 TS 的精度更高,WHERE 子句中的检查会阻止它找到刚刚插入的行。
问题:抛开我将DATETIME列作为PK一部分的原因,我如何使EF插入行而不抛出异常?
我可以将 我加倍检查了一下,TS 列设为DATETIME2 类型,这将解决问题,但我不想仅仅因为一些 EF 问题而浪费数据库空间。DATETIME 和 DATETIME2 似乎都占用了 8 个字节,所以我想我是这样的。
我可以在文本编辑器中编辑.edmx 文件并让它认为主键只是Id 列(所以EF 不会在插入后使用TS 来查找Id),但VS 会覆盖我的下次我从 DB 更新实体时进行编辑。
还有其他选择吗?
【问题讨论】:
-
也许有更好的解决方案,但您可以使用 Stored proc 作为最后的手段插入 db。
-
您需要在模型中指定您使用复合主键,否则 EF 将永远无法工作,请参阅此帖子 stackoverflow.com/questions/14873169/…
-
我使用数据库优先的方法,所以 EF 非常了解我有复合主键。
标签: c# sql-server entity-framework-5