具有以下TestClass
:
[Table("xyz")]
public partial class TestClass{
[Key]
public int key {get; set;}
[ForeignKey("key")]
public virtual ICollection<ExternalClass> externalClasses{get; set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
...
}
}
我该如何设置该类以满足我的以下要求:
externalClasses
不应保存(应该已经在数据库中)我的第一个想法是将外来对象设置为null,并在validate方法内请求数据库检查外键是否存在。但是这种方法不适用于单元测试,而且在我看来,在模型中包含数据库请求也不是很干净。
有人知道如何使用EF以干净的方式处理该问题吗?
答案 0 :(得分:1)
我认为在模型中包含数据库请求并不是很干净
我倾向于同意,但是为了验证,我倾向于提出一个例外。为什么?
当决定由IValidatableObject
完成验证时,应该尽可能唯一地验证 (这意味着Validate
方法不是进行涉及其他实体的更复杂验证的最佳位置。
将“简单”验证规则的一部分包含在实体本身中,而将--well的另一部分包含在任何地方,将非常不便。这就是问题所在:它可以在任何地方。因此,在通过另一个代码路径保存实体时可以跳过它。
因此,我倾向于将执行验证的上下文提供给validationContext
。这是通过覆盖ValidateEntity
调用的上下文SaveChanges
方法(当context.Configuration.ValidateOnSaveEnabled
为true
时)完成的:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
items.Add("context", this);
return base.ValidateEntity(entityEntry, items);
}
现在可以在Validate
方法内获取上下文的句柄了:
var context = (MyContext)validationContext.Items["context"];
...它可用于执行数据库查询。
这应该小心处理。遵守以下三个规则是很好的:
IValidatableObject
并不是最好的主意。)有了这个,就可以运行像这样的验证了:
var ids = externalClasses.Select(c => c.ID).ToList();
if (context.ExternalClasses.Any(c => !ids.Contains(c.ID))
{
yield return new ValidationResult("Some external classes don't exist",
new[] { nameof(externalClasses) });
}
这将执行相对轻量级的查询,该查询仅返回布尔值,并且不将新实体附加到变更跟踪器。
答案 1 :(得分:0)
直到现在我已经解决了以下问题:
我按如下方式创建了实体类((通过使用单个异物而不是ICollection简化了示例):
[Table("xyz")]
public partial class TestClass{
[Key]
public int key {get; set;}
[ForeignKey("key")]
[Required]
public virtual ExternalClass externalClass{get; set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
...
}
}
然后在我的ServiceClass
中创建新记录的地方:
public void InsertNewRecord(TestClass newClass){
newClass.externalClass = context.Where(e => e.ID = newClass.externalClass.Id).First();
context.Add(newClass);
context.SaveChanges();
}
如果找不到externalClass(外部),则将newClass.externalClass
设置为null,并由于[Required]
注释而引发验证错误。这样做还有一个好处,就是EF不会尝试保存异物externalClass
,因为它现在识别出该条目仍然存在。