基于Entity Framework的DI(依赖注入)实现

3
我想在实体类中添加一个验证类,以便在将其输入数据库之前检查其是否有效。(检查是为了业务需求而非数据库限制)。
我已经有这个类。
public class MyEntity
{
     private readonly IValidatorFactory _validatorFactory;
     public MyEntity(IValidatorFactory validatorFactory)
     {
         _validatorFactory = validatorFactory;
     }

     //Entity Properties Removed For Clarity

     public void Validate()
     {
         if(_validatorFactory == null)
         {
                throw new ArgumentNullException("Validator Factory was null, cannot validate this item");
         }

         var validator = _validatorFactory.GetValidator(this.ItemTypeId);
         valid = validator.Validate();

     }
}

使用依赖注入,我很难看到如何在项目中使用EF6时干净地解决依赖关系。如果我返回一个DbSet,它当然不知道验证器的要求。需要使用一个无参构造函数。


验证(Validate)将在数据导入系统时使用,为此可以注入工厂并且我可以拥有一个无参数构造函数以进行选择。如果实体正在被更改和更新,则后续可能会出现问题,在允许最终保存之前需要在控制器上调用validate()。 - Lotok
@MarkSeemann,我不确定我同意将依赖注入到实体中违反了单一职责原则。这样做实际上允许另一个类处理验证,这正是SR的全部内容。它还符合开闭原则,因为使用接口允许多态/扩展而不是编辑。我本来可以让服务层处理验证,但那样就会向无血缘反模式和过程化代码靠拢。 - Lotok
@James,为什么要使用工厂、验证器和所有这些花里胡哨的东西?从抽象验证器的概念中你能得到什么好处? - guillaume31
@guillaume31 它允许我根据实体的类型传递不同的验证类。所涉及的实体大约有4种不同类型,具有相同的属性但具有不同的业务要求和验证规则。这似乎是使用多态性将验证器抽象化的完美例子,以便客户端不需要知道它正在处理哪种类型的实体。 - Lotok
1
为什么不使用访问者或管道模式呢?这样你就不需要对实体进行任何更改。你只需将要验证的实体传递给验证器即可。 - Matthew Whited
显示剩余6条评论
2个回答

4
首先,我认为您不应该尝试在实体中使用DI。验证应该在实体本身内部进行,而不是使用外部验证器(传递到Validate方法或使用ValidatorFactory创建)。
Entity Framework已经内置了多种验证方式。您尝试过其中任何一种吗?
最简单的形式是向属性添加属性,例如RequiredStringLength。对于更复杂的验证,您可以使实体实现IValidateObject或覆盖DbContext.ValidateEntity

使用任何一种方法,当验证失败时,调用DbContext.SaveChanges将会引发DbEntityValidationException。您也可以通过调用DbContext.GetValidationErrors触发验证而不抛出异常。


2

对我来说,需要一个外部验证器就像是一种气味 - 更不用说复杂的ValidatorFactory了。

如果你想避免贫血领域反模式,正如你所说,你可以将验证包含在实体本身中,并保持它们始终有效

我觉得另一件没有意义的事情是,你确定了4个具有“不同业务要求和验证规则”的实体。在我看来,这正是你需要特定于每个实体内部强制执行其自己规则的临时实体的特殊性,而不是外部验证器抽象的通用性。

关于你的4个实体的相似部分,即数据,我会尝试将其提取到有意义的值对象中,并由这些对象组成你的实体。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接