针对数据库的 EF 模型验证

本文关键字:模型 验证 EF 数据库 | 更新日期: 2023-09-27 18:35:33

我想使用 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 之外,只是找不到在模型类中使用它的方法,但我觉得这不是正确的解决方案。

有没有更好的"正确"方法来实现这种验证?

提前谢谢。

针对数据库的 EF 模型验证

当你必须去数据库时,你需要使用DbContextDbContext有一个叫做ValidateEntity的可覆盖方法。请参阅本文:实体框架验证。

把我使用的代码放在另一个答案中

更多关于我如何在 MVC 中构建验证的信息 这里.

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

您可以使用任何可用的IOC容器(如Unity,Ninject,Autofac或StructureMap)将存储库注入为依赖项。

这样,您将能够访问控制器、Validate 方法或需要使用它的任何位置中的同一对象。

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

使用Ninject的示例:

您创建一个全局可访问(设计取决于您)的 nin注入内核

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());

,并以与在控制器工厂中类似的方式在验证方法中获取存储库。