【发布时间】:2018-08-07 11:50:06
【问题描述】:
我对实体框架生成的 sql 语句组合有疑问。
看起来 powerloss 字段的更新值没有在更新语句完成并执行 select 后立即设置。
我不知道这是否可能。 也许我只是错过了一些东西。
代码执行后更新和选择的行和表中的数据都是正确的。
它应该做什么(并且它 99% 的时间都在做)
我从设备获取 counterValue 并将其插入到 sql-server 2008 R2 (SP3) 上的表中。如果设备断电并且在某个时刻又回来了,则数据库中最后一个 counterValue 条目中的字段“powerloss”将更新为 1(true)。默认情况下,该字段为 0(false)。
之后,我查询这个设备的最后一个 counterValue 并取反。 但仅当“powerloss”字段为 0(假)时。否则查询必须返回零。
出了什么问题
有时(非常罕见)当 powerloss 字段在选择之前更新为 1(true) 时,我得到否定的 counterValue...
这至少是我的日志文件向我显示的内容(记录了每个查询)。
代码的作用
- 创建 dbContext
- BeginTransaction(isolationLevel.ReadComitted)
-
WriteNewCounterValue(断电后)
更新字段
powerloss=true-
根据 powerloss 字段中的值选择 counterValue
offset = (From qItem In DB.SlaveCounterEntries Where qItem.deviceId= deviceId And qItem.Received < timestamp Order By qItem.Received Descending Select If(qItem.Powerloss = True, 0, -qItem.CounterValue) Take 1).SingleOrDefault() 在表中插入新的 counterValue
- 提交事务
- 处置 dbContext
生成的 sql 语句
更新声明:
UPDATE [dbo].[slaveCounter]
SET [powerloss] = @0
WHERE ([id] = @1)
-- @0: 'True' (Type = Boolean)
-- @1: '3371747' (Type = Int32)
-- Executing at 29.06.2018 05:57:24 +02:00
-- Completed in 0 ms with result: 1
select 语句(更新后 14 毫秒):
SELECT TOP (1)
[Project1].[C1] AS [C1]
FROM ( SELECT
CASE WHEN (1 = [Extent1].[powerloss]) THEN 0 ELSE -([Extent1].[counterValue]) END AS [C1],
[Extent1].[datReceived] AS [datReceived]
FROM [dbo].[slaveCounter] AS [Extent1]
WHERE ([Extent1].[slaveId] = @p__linq__0) AND ([Extent1].[datReceived] < @p__linq__1)
) AS [Project1]
ORDER BY [Project1].[datReceived] DESC
-- p__linq__0: '48' (Type = Int16, IsNullable = false)
-- p__linq__1: '28.06.2018 23:00:03' (Type = DateTime2, IsNullable = false)
-- Executing at 29.06.2018 05:57:24 +02:00
-- Completed in 0 ms with result: SqlDataReader
【问题讨论】:
-
如果更新后14ms,可能还没有提交。
-
如果他不使用 NOLOCK,他将如何读取未提交的数据?更新在事务中。他是否也可以保存时间戳,然后也记录下来?
-
事务只确保数据被读取,就好像它是按顺序完成的一样,不保证实际的顺序。
-
这里没有足够的信息来完全理解发生了什么。
-
qItem.Received是否保证唯一?
标签: sql .net sql-server entity-framework tsql