使用 ValidateEntity 实现唯一约束会给出“字典中不存在给定的键”错误
在尝试使用 EF CodeFirst/Mvc3 为我的数据库实现唯一的密钥验证时,我发现了这篇文章 http://blogs.msdn.com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspx 其中给出了如何执行此操作的示例通过使用 IValidateObject
作为我的对象模型:
public class Category : IValidatableObject
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var testContext = (TestContext)validationContext.Items["Context"];
if (testContext.Categories.Any(
c => c.CategoryName == CategoryName && c.CategoryID != CategoryID))
{
yield return new ValidationResult("A category with the same name already exists!", new[] { "CategoryName" });
}
yield break;
}
}
并覆盖 DbEntityValidationResult ValidateEntity
:
public class TestContext : DbContext
{
public DbSet<Test.Models.Category> Categories { get; set; }
protected override DbEntityValidationResult ValidateEntity( DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var myItems = new Dictionary<object, object>();
myItems.Add("Context", this);
return base.ValidateEntity(entityEntry, myItems);
}
}
以及控制器上的操作
[HttpPost]
public ActionResult Create(Category category)
{
if (ModelState.IsValid) {
categoryRepository.InsertOrUpdate(category);
categoryRepository.Save();
return RedirectToAction("Index");
} else {
return View();
}
}
但我收到错误:“给定的键字典中不存在。”
var testContext = (TestContext)validationContext.Items["Context"];
这行似乎正在调用对象上的 Validate,该对象在覆盖 ValidateEntity 代码中设置之前访问“Context”。
起初我以为可能是 ModelState.Isvalid 过早触发验证,但事实并非如此。
有人知道我在这里缺少什么或者我做错了什么吗?提前致谢。
While in search of trying to implement unique key validations for my db using EF CodeFirst/Mvc3 I came upon this post http://blogs.msdn.com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspx which gave an example on how to do it by using IValidateObject
for my object model:
public class Category : IValidatableObject
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var testContext = (TestContext)validationContext.Items["Context"];
if (testContext.Categories.Any(
c => c.CategoryName == CategoryName && c.CategoryID != CategoryID))
{
yield return new ValidationResult("A category with the same name already exists!", new[] { "CategoryName" });
}
yield break;
}
}
and overriding DbEntityValidationResult ValidateEntity
:
public class TestContext : DbContext
{
public DbSet<Test.Models.Category> Categories { get; set; }
protected override DbEntityValidationResult ValidateEntity( DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var myItems = new Dictionary<object, object>();
myItems.Add("Context", this);
return base.ValidateEntity(entityEntry, myItems);
}
}
And the action on the controller
[HttpPost]
public ActionResult Create(Category category)
{
if (ModelState.IsValid) {
categoryRepository.InsertOrUpdate(category);
categoryRepository.Save();
return RedirectToAction("Index");
} else {
return View();
}
}
But I get the error: "The given key was not present in the dictionary."
for the line
var testContext = (TestContext)validationContext.Items["Context"];
It seems like Validate on the object is getting called which accesses "Context" before its set in the override ValidateEntity code.
At first I thought it could have been ModelState.Isvalid triggering validate too early but it wasn't.
Anyone know what I'm missing here or what I'm doing wrong? Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Model.IsValid
肯定会过早触发它,也许还有其他原因。IValidatableObject
是 MVC 和 EF 使用的全局接口,但仅当您在上下文上调用SaveChanges
时才会调用DbContext
中的方法,因此任何使用在调用SaveChanges
之前的IValidatableObject
将导致异常。如果您想以这种方式验证实体,则必须使用另一种方法。例如,将上下文存储在 HttpContext.Items 中 - 您可以创建自定义操作过滤器,并在操作调用之前实例化和存储上下文,并在操作调用之后对其进行处置 - 希望它能够解决所有问题。Model.IsValid
definitely triggers it too early and perhaps something else.IValidatableObject
is global interface used by both MVC and EF but your method inDbContext
is called only when you callSaveChanges
on the context so any usage ofIValidatableObject
prior to callingSaveChanges
will result in the exception. You must use another approach if you want to validate your entity this way. For example store context inHttpContext.Items
- you can create custom action filter and instantiate and store the context before the operation call and dispose it after operation call - hopefully it will cover all problems.我面临着同样的问题......然后经过大量谷歌搜索我终于找到了这个:
练习3:使用 IValidatableObject 自定义验证
正如您在示例中看到的,它们实例化了一个新的
Context
,因此没有需要validationContext.Items["Context"];
。这样做我们就不会再出现这个错误了。I was facing the same problem... Then after a lot of Googling I finally found this:
Exercise 3: Using IValidatableObject Custom Validation
As you see in their example, they instantiate a new
Context
and as such there's no need forvalidationContext.Items["Context"];
. Doing so we won't get this error anymore.