针对数据库的EF模型验证

时间:2013-10-16 14:24:37

标签: c# entity-framework validation asp.net-mvc-4

我想使用EF 5模型验证来避免数据库中的重复值,所以我使用的是这样的模型类:

[Table("MeasureUnits")]
public class MeasureUnit : IValidatableObject
{
    public int MeasureUnitId { get; set; }

    public string Symbol { get; set; }

    public string Name { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        using (MeasureUnitRepository rep = new MeasureUnitRepository())
        {
            MeasureUnit measureUnit = rep.FindDuplicateBySymbol(this);

            if (measureUnit != null)
                yield return new ValidationResult(
                    "There is another unit with this symbol, you can't duplicate it", 
                    new[] { "Symbol" });
        }
    }

存储库类创建DbContext,实现IDisposable,具有查找副本的逻辑,并且一切都按预期工作。

但是,使用调试器我意识到每次插入或更新都会执行两次验证,因此存储库(和DbContext)也会被实例化并处理两次。

除此之外,控制器中还有另一个DbContext但是在模型类中找不到使用它的方法,除了在模型的构造函数中包含DbContext,但我觉得它不是正确的解决方案。 / p>

是否有更好的“正确”方式来实现此验证?

提前致谢。

2 个答案:

答案 0 :(得分:2)

当您必须转到数据库时,您需要使用DbContextDbContext有一个名为ValidateEntity的可覆盖方法。请参阅此文章:Entity Framework Validation

我将我使用的代码放在另一个答案here

更多关于我structured the validation in MVC的信息。

此外,在您的存储库中实例化上下文可能会让您感到悲伤。存储库需要共享上下文。您可以将上下文视为您的工作单元并将其传递到构造函数中的存储库中,或者您可以将上下文包装在您自己的工作单元中并将其传递。

答案 1 :(得分:1)

您可以使用IOCUnityNinjectAutofac之类的任何StructureMap容器来将您的存储库作为依赖项注入。

通过这种方式,您可以访问控制器中的同一对象,验证方法或需要使用它的任何位置。

其中一些IOC(Ninject肯定 - 寻找'请求范围')容器能够与ASP.NET MVC集成,以便每个请求创建一次依赖项(在这种情况下是您的存储库)并在请求时处理结束。

使用Ninject的示例:

您可以创建一个全局可访问的(设计由您决定)ninject内核

public static class NinjectKernel
{
    public static IKernel Kernel = new StandardKernel();
    static NinjectKernel()
    {
        Kernel.Bind<IMyRepository>().To<MyRepositoryImpl>().InRequestScope();
    }
}

和MVC控制器的控制器工厂

public class NinjectControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext,
    Type controllerType)
    {
        return controllerType == null ? null : (IController)NinjectKernel.Kernel.Get(controllerType);
    }
}

然后,您可以像这样

在Global.asax中设置控制器工厂
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());

并以与在Controller工厂中完成的方式类似的方式获取Validate方法中的存储库。