我有一个数据结构,使得:OptimisticConcurrencyException实体框架上的UPDATE,影响0行
SECURITYPOLICY 1 < --- * SecurityPolicyRule
因此,SECURITYPOLICY可以有0个,一个或多个SecurityPolicyRules。
我正在使用Julie Lerman的实体框架书来实现某种程度的并发检查,TDD和POCO支持。
我知道每个表都应该有一个rowversion/timestamp字段,它被标记为ConcurrencyMode == Fixed。
我决定在存储过程中实施CUD。我的UPDATE存储过程如下:
create PROCEDURE dbo.sp_M2_Core_UpdateSecurityPolicy
@ID int,
@Name nvarchar(256),
@Comment nvarchar(max)=null,
@timestamp timestamp
AS
declare @nameExists nvarchar(256)
select @nameExists= [Name] from M2_Core_SecurityPolicy where [Name][email protected] and [ID]<>@id
if (not @nameExists is null)
begin
raiserror (N'Name is already in use: %s',
11,
1,
@Name)
end
else
begin
update M2_Core_SecurityPolicy
set [Name][email protected],
[Comment][email protected]
where [email protected] and [timestamp][email protected]
IF @@ROWCOUNT>0
SELECT [Timestamp] AS newTimeStamp FROM M2_Core_SecurityPolicy WHERE [email protected]
end
go
create PROCEDURE dbo.sp_M2_Core_UpdateSecurityPolicyRule
(
@id int,
@RoleName nvarchar(256),
@Rank int,
@CanReadExecute bit=null,
@CanWrite bit=null,
@CanDelete bit=null,
@CanExport bit=null,
@Timestamp timestamp
)
AS
declare @roleExists nvarchar(256)
declare @securityPolicyID int
select @roleExists= [RoleName] from vw_aspnet_Roles where [RoleName][email protected]
if (@roleExists is null)
begin
raiserror (N'Role is not defined: %s',
11,
1,
@roleName)
end
else
begin
select @securityPolicyID=[SecurityPolicyID] from M2_Core_SecurityPolicyRule where [id][email protected]
-- move all other rules up in priority
IF (SELECT COUNT(*) FROM M2_Core_SecurityPolicyRule WHERE [ID]<>@ID AND [SecurityPolicyID][email protected] AND [Rank][email protected]) > 0
BEGIN
UPDATE M2_Core_SecurityPolicyRule
SET [Rank]=[Rank]+1
WHERE [Rank] >= @rank
AND [SecurityPolicyID][email protected]
AND [ID]<>@ID
END
update M2_Core_SecurityPolicyRule
set [RoleName][email protected],
[Rank][email protected],
[CanReadExecute][email protected],
[CanWrite][email protected],
[CanDelete][email protected],
[CanExport][email protected]
where [email protected] and [timestamp][email protected]
IF @@ROWCOUNT>0
SELECT [Timestamp] AS newTimeStamp FROM M2_Core_SecurityPolicyRule WHERE [email protected]
end
RETURN
go
我测试这个使用一些代码:
- 创建一个安全策略
- 添加一个创建的安全策略规则的安全策略
- 再添安全策略
- 保存更新
- 将1添加到安全策略规则的等级
- 保存更新
测试低于:
[TestMethod()]
public void AddWithSecurityPolicyRuleChangeRankTest()
{
ICoreContext coreContext = new CoreEntities(_coreDbConnectionString);
CoreUnitOfWork coreUnitOfWork = new CoreUnitOfWork(coreContext);
SecurityPolicyRepository target = new SecurityPolicyRepository(coreUnitOfWork);
int originalCount = coreContext.SecurityPolicies.Count();
string securityPolicyName = "addwithsecuritypolicyrulechangeruletest";
int originalRank = 1;
SecurityPolicy entity = new SecurityPolicy()
{
Comment = null,
Name = securityPolicyName,
SecurityPolicyRules = new FixUpCollection<SecurityPolicyRule>()
};
entity.SecurityPolicyRules.Add(
new SecurityPolicyRule()
{
CanDelete = null,
CanExport = null,
CanReadExecute = null,
CanWrite = null,
Rank = originalRank,
RoleName = "User"
});
target.Add(entity);
coreUnitOfWork.Save();
entity.SecurityPolicyRules[0].Rank=originalRank+1;
coreUnitOfWork.Save(); // <-- exception thrown here
SecurityPolicy savedSecurityPolicy = target.GetAll().Single(q => q.Name.Equals(securityPolicyName, StringComparison.CurrentCultureIgnoreCase));
Assert.AreEqual(originalRank+1,savedSecurityPolicy.SecurityPolicyRules[0].Rank);
}
然而,当我运行它,它抛出在突出显示的行异常。唯一的例外是:
System.Data.OptimisticConcurrencyException 了未处理由用户代码
消息=商店更新,插入,或 删除语句受影响的行(0)的 意想不到数。 实体可能已被修改或 已删除,因为实体已加载。 刷新ObjectStateManager条目。
源= System.Data.Entity的
堆栈跟踪: 在System.Data.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64类型 的RowsAffected,更新命令源) 在System.Data.Mapping.Update.Internal.UpdateTranslator。更新(IEntityStateManager stateManager,IEntityAdapter适配器) 在System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache) 在System.Data.Objects.ObjectContext.SaveChanges(SaveOptions 选项) 在System.Data.Objects.ObjectContext .SaveChanges() at MIGTurbo2.Core.Data.CoreEntities.Save()在 d:\ dev的\ migturbo2.0 \ MIGTurbo2.Core \数据\ Core.Context.cs:线在MIGTurbo2.Repositories.CoreUnitOfWork.Save() 在 d:\ dev的\ migturbo2.0 \ MIGTurbo2.Repositories \ CoreUnitOfWork.cs:行在MIGTurbo2.Core.Tests。IntegrationTests.SecurityPolicyRepositoryTest.AddWithSecurityPolicyRuleChangeRankTest() 在 d:\ dev的\ migturbo2.0 \ MIGTurbo2.Core.Tests \ IntegrationTests \ SecurityPolicyRepositoryTest.cs:行 524的InnerException:
果然,没有数据已经改变。即。 [Rank]在第一次更新时仍然是1(因此,INSERT)。但是,通过SQL Profiler和Ayende的EF Profiler运行它,甚至不需要调用数据库来进行更新。所以时间戳/ rowversion的相关性肯定是不相关的?
这可能是什么原因造成的?我不想在每次保存时刷新数据库!
更新1
已经运行应该执行SQL:
declare @t timestamp
select @t=[timestamp] from M2_Core_SecurityPolicyRule where ID=1
exec [sp_M2_Core_UpdateSecurityPolicyRule] @id=1, @roleName='User',@Rank=2,@[email protected]
它工作正常。有内部发生的是EF东西阻塞调用
更新2
通过通过密码破译,我觉得会出现以下情况:
- 创建的项目(明显,时间戳为空)
- 该项目被添加(时间戳仍为空)
- 保存的更改(此问题INSERT)
- 的[时间戳]字段,然后不从DB
- 因此更新后,后续的更新失败,因为[时间戳] IS NULL
那么,为什么会在[时间戳]字段不能更新?
感谢Amasuriel。我已经更新了我的问题以包含我的新发现(更新2)。由于我正在抽象出EF,我会发现很难使用Context.Refresh,因为我需要发送需要刷新的确切对象。另外,我想避免这种情况。数据库没有任何活动。这是“从记忆中”发生的。 – 2011-06-13 09:07:25