5

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

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

提前致谢。

4

2 回答 2

2

当您必须访问数据库时,您需要使用DbContextDbContext拥有一个称为 Overridable 的方法ValidateEntity。请参阅这篇文章:实体框架验证

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

以及更多关于我如何在 MVC 中构建验证的信息。

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

于 2013-10-16T15:06:29.270 回答
1

您可以使用任何可用的IOC容器,如UnityNinjectAutofacStructureMap将您的存储库作为依赖项注入。

通过这种方式,您将能够访问控制器中的相同对象、您的 Validate 方法或您需要使用它的任何地方。

其中一些 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());

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

于 2013-10-16T14:37:41.827 回答