C# 实体框架-外键验证
具有以下C# 实体框架-外键验证,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,具有以下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&
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)
{
...
}
}
[表(“xyz”)]
公共部分类TestClass{
[关键]
公共int密钥{get;set;}
[外国钥匙(“钥匙”)]
公共虚拟ICollection外部类{get;set;}
公共IEnumerable验证(ValidationContext ValidationContext)
{
...
}
}
我需要如何设置该类以满足以下要求:
- 我想用实体框架单元测试来测试模型
- 在生产环境中,
不应该保存(应该已经在数据库中)externalClasses
- EF必须确保每个外部类都存在于DB中。如果不是,抛出异常
Validate
方法不是应用涉及其他实体的更复杂验证的最佳场所)
将“简单”验证规则的一部分放在实体本身中,另一部分放在任何地方都会非常不方便。这就是问题所在:它可以在任何地方。因此,当通过另一个代码路径保存实体时,可以跳过它
因此,我倾向于将执行验证的上下文提供给validationContext
。这是通过重写上下文的ValidateEntity
方法完成的,该方法由SaveChanges
调用(当context.Configuration.ValidateOnSaveEnabled
为true
时):
…并可用于执行数据库查询
不过,这应该小心处理。遵守三条规则很好:
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) });
}
这将执行一个相对较轻的查询,只返回一个布尔值,不会将新实体附加到更改跟踪器。直到现在,我解决了以下问题: 我创建了entity类,如下所示(通过使用单个外部对象而不是ICollection简化了示例):
如果找不到externalClass(外部),则会将
newClass.externalClass
设置为null,并由于[必需]
注释而引发验证错误。这还有一个额外的优点,EF不会试图保存外部对象externalClass
,因为它现在识别出这个条目仍然存在。我们可以通过在单元测试中模拟这些功能来禁止保存在externalClass上的数据。例如:你可以使用MoQ,RhinoMock@SULFIKAR啊,对不起。。我忘了提到我确实使用最小起订量。但我不确定在模型验证方法中包含数据库请求是否干净。没有其他解决方案吗?此外,我总是需要手动从外部对象填充外键,这是一个难题。如果有任何解决方案,EF会自动将对象映射到外键,那就太好了。哇,非常感谢您的精彩和广泛的解释。这对我理解EF的用法和模式有很大帮助。非常感谢。
var context = (MyContext)validationContext.Items["context"];
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) });
}
[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)
{
...
}
}
public void InsertNewRecord(TestClass newClass){
newClass.externalClass = context.Where(e => e.ID = newClass.externalClass.Id).First();
context.Add(newClass);
context.SaveChanges();
}