asp.net-mvc – 使用Web API不检查的并发检查
使用EntityFramework v6,我整理了一个原型来演示Web Api和桌面应用程序中的并发检查.
实体: public static class IRowVersionExtensions { public static string RowVersionAsString(this IRowVersion ivr) { return Convert.ToBase64String(ivr.RowVersion); } public static void SetRowVersion(this IRowVersion ivr,string rowVersion) { ivr.RowVersion = Convert.FromBase64String(rowVersion); } } public interface IRowVersion { byte[] RowVersion { get; set; } } public class Department : IRowVersion { [Key] public int Id { get; set; } [Required,MaxLength(255)] public string Name { get; set; } public string Description { get; set; } [Timestamp] [ConcurrencyCheck] public byte[] RowVersion { get; set; } } 的DbContext: public class CompDbContext : DbContextEx { public CompDbContext() : base("Company") { this.Configuration.LazyLoadingEnabled = false; } public DbSet<Department> Departments { get; set; } } 桌面应用程序(控制台应用程序)具有以下代码,并按预期抛出DbConcurrencyException:http://pastebin.com/i6yAmVGc 现在,API控制器 – 当我在两个窗口中打开页面并编辑一个(并保存)然后尝试编辑/保存另一个时,它不会抛出异常: Api控制器更新操作: [HttpPatch,Route("")] public Department UpdateDepartment(Department changed) { var original = dbContext.Departments.Find(changed.Id); if (original == null) this.NotFound(); if (Convert.ToBase64String(changed.RowVersion) != Convert.ToBase64String(original.RowVersion)) Console.WriteLine("Should error."); original.RowVersion = changed.RowVersion; original.Name = changed.Name; original.Description = changed.Description; dbContext.SaveChanges(); return original; } Api电话: DepartmentVM.prototype.onSave = function (entity) { var method = entity.id() ? 'PATCH' : 'PUT'; $.ajax({ url: '/api/departments',method: method,data: ko.toJSON(entity),contentType: 'application/json',dataType: 'JSON' }) .done(function (data) { alert('Saved'); entity.rowVersion(data.rowVersion); entity.id(data.id); }) .error(function (data) { alert('Unable to save changes to department.'); }); }; 当我在控制器动作中断行时: if (Convert.ToBase64String(changed.RowVersion) != Convert.ToBase64String(original.RowVersion)) 在第一次保存时,changed.RowVersion == original.RowVersion(完美)并保存(如预期的那样).在第二页的保存中,changed.RowVersion!= original.RowVersion(完美)但它仍然保存,没有异常(不是预期的). 有人可以帮助我理解为什么它在桌面应用程序中运行良好但在Web API中不起作用? 解决方法
它不起作用,因为EF使用RowVersion的“原始”值来执行并发检查.在您的示例中,原始值(就DbContext而言)是数据库中的值,因为它是使用.Find()从数据库加载的.
比方说,例如,已更改实体的RowVersion为1,数据库中的当前RowVersion为2 … // changed's RowVersion is 1 var original = dbContext.Departments.Find(changed.Id); // original's RowVersion is 2 if (original == null) this.NotFound(); if (Convert.ToBase64String(changed.RowVersion) != Convert.ToBase64String(original.RowVersion)) Console.WriteLine("Should error."); // 2 != 1,so prints this line original.RowVersion = changed.RowVersion; // original's "current" RowVersion is now 1 // ... but its "original" RowVersion is still 2! original.Name = changed.Name; original.Description = changed.Description; dbContext.SaveChanges(); // UPDATE DEPT SET ... WHERE Id = ... AND RowVersion = 2 // (works,therefore no concurrency exception) 要使其工作,您只需将传入的实体添加到上下文中…… [HttpPatch,Route("")] public Department UpdateDepartment(Department changed) { dbContext.Entry(changed).State = EntityState.Modified; dbContext.SaveChanges(); // you'll get an exception if RowVersion has changed return changed; } 如果您只想更改名称和描述,则可以选择性地将这些属性标记为已更改,其余属性不会更新… [HttpPatch,Route("")] public Department UpdateDepartment(Department changed) { dbContext.Entry(changed).State = EntityState.Unchanged; dbContext.Entry(changed).Property(d => d.Name).IsModified = true; dbContext.Entry(changed).Property(d => d.Description).IsModified = true; dbContext.SaveChanges(); // you'll get an exception if RowVersion has changed return changed; } 控制台应用程序工作的原因有点幸运.存在竞争条件,如果t1中的Find()在t2中的SaveChanges()之后执行(反之亦然),则会遇到相同的情况. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – 如何更改当前文化的数据格式,以便它适用于整个W
- asp.net-core-mvc – MVC核心如何强制/设置所有操作的全局授
- asp.net – 获取Gridview中隐藏列的值
- asp.net-mvc – 发生异常后不要刷新会话 – NHibernate
- Asp.Net Core 生成二维码(NuGet使用QRCoder)
- iis-7 – ASP 3.0应用程序对象
- asp.net – 在WiX安装程序中的应用程序池上设置禁用重叠循环
- Asp.net Mvc 6登录后立即获得用户声明
- IIS ASP.NET WebApi在请求同一台服务器时死锁
- asp.net – 如何为我的网站关闭IIS中的自定义错误处理?
- C#_.NetFramework_Web项目_NPOI_EXCEL数据导入
- asp.net-mvc – 如何在Asp.net MVC中添加WebApi,
- asp.net-mvc – MVC模型绑定:为什么我不能绑定到
- asp.net-mvc-4 – 如何为OData服务配置Upshot.js
- asp.net – Web API将OAuth令牌作为XML返回
- 从Azure功能调用Asp.Net Web API端点
- asp.net-mvc-3 – asp.net mvc 3.0客户端验证无效
- asp.net-mvc-4 – 用于继承类型的WebApi模型绑定
- asp.net – 配置IIS服务器使用Aurelia框架并推送
- asp.net-mvc-3 – 使用csvhelper(nuGET)和C#MVC导