.net – 从何处运行实体的重复检查

前端之家收集整理的这篇文章主要介绍了.net – 从何处运行实体的重复检查前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在寻找关于“最佳”放置验证逻辑的建议,例如在MVC应用程序中使用Entity Framework Code-First时对实体进行重复检查.

使用一个简单的例子:

public class JobRole
{
  public int Id { get; set; }        
  public string Name { get; set; }
}

规则是“名称”字段必须是唯一的.

当我添加一个新的JobRole时,很容易在Job Role Repository中运行一个名称尚不存在的检查.

但是,如果用户编辑现有JobRole,并意外将名称设置为已存在的名称,我该如何检查?

问题是存储库中不需要“更新”方法,因为作业角色实体将自动检测更改,因此在尝试保存之前没有合理的位置来执行此检查.

到目前为止,我考虑了两个选项:

>覆盖DbContext上的ValidateEntry方法,然后在使用EntityState.Modified保存JobRole实体时,运行重复检查.
>在尝试保存之前,创建一些从Controller调用的重复检查服务.

两者都不是真的很理想.使用ValidateEntry似乎相当晚(在保存之前)并且难以测试.使用服务可能会有人忘记从控制器调用它,让重复的数据通过.

有没有更好的办法?

解决方法

您对ValidateEntity的问题似乎是在SaveChanges上进行验证,这对您来说太迟了.但是在Entity Framework 5.0中,如果您希望使用 DbContext.GetValidationErrors,则可以提前调用验证.当然,您也可以直接调用 @L_403_1@.我是这样做的:

>覆盖DbContext上的ValidateEntity方法

protected override DbEntityValidationResult 
                   ValidateEntity(DbEntityEntry entityEntry,IDictionary<object,object> items)
{
    //base validation for Data Annotations,IValidatableObject
    var result = base.ValidateEntity(entityEntry,items);

    //You can choose to bail out before custom validation
    //if (result.IsValid)
    //    return result;

    CustomValidate(result);
    return result;
}

private void CustomValidate(DbEntityValidationResult result)
{
    ValidateOrganisation(result);
    ValidateUserProfile(result);
}

private void ValidateOrganisation(DbEntityValidationResult result)
{
    var organisation = result.Entry.Entity as Organisation;
    if (organisation == null)
        return;

    if (Organisations.Any(o => o.Name == organisation.Name 
                               && o.ID != organisation.ID))
        result.ValidationErrors
              .Add(new DbValidationError("Name","Name already exists"));
}

private void ValidateUserProfile(DbEntityValidationResult result)
{
    var userProfile = result.Entry.Entity as UserProfile;
    if (userProfile == null)
        return;

    if (UserProfiles.Any(a => a.UserName == userProfile.UserName 
                              && a.ID != userProfile.ID))
        result.ValidationErrors.Add(new DbValidationError("UserName","Username already exists"));
}

>在try catch中嵌入Context.SaveChanges并创建一个访问Context.GetValidationErrors()的方法.这是在我的UnitOfWork类中:

public Dictionary<string,string> GetValidationErrors()
{
    return _context.GetValidationErrors()
                   .SelectMany(x => x.ValidationErrors)
                   .ToDictionary(x => x.PropertyName,x => x.ErrorMessage);
}

public int Save()
{
    try
    {
        return _context.SaveChanges();
    }
    catch (DbEntityValidationException e)
    {
        //http://blogs.infosupport.com/improving-dbentityvalidationexception/
        var errors = e.EntityValidationErrors
          .SelectMany(x => x.ValidationErrors)
          .Select(x => x.ErrorMessage);

        string message = String.Join("; ",errors);

        throw new DataException(message);
    }
}

>在我的控制器中,在将实体添加到上下文之后但在SaveChanges()之前调用GetValidationErrors():

[HttpPost]
public ActionResult Create(Organisation organisation,string returnUrl = null)
{
    _uow.OrganisationRepository.InsertOrUpdate(organisation);

    foreach (var error in _uow.GetValidationErrors())
        ModelState.AddModelError(error.Key,error.Value);

    if (!ModelState.IsValid)
        return View();

    _uow.Save();

    if (string.IsNullOrEmpty(returnUrl))
        return RedirectToAction("Index");

    return Redirect(returnUrl);
}

我的基础存储库类实现了InsertOrUpdate,如下所示:

protected virtual void InsertOrUpdate(T e,int id)
    {
        if (id == default(int))
        {
            // New entity
            context.Set<T>().Add(e);
        }
        else
        {
            // Existing entity
            context.Entry(e).State = EntityState.Modified;
        }      
    }

我仍然建议为数据库添加一个唯一约束,因为这绝对可以保证您的数据完整性并提供可以提高效率的索引,但是覆盖ValidateEntry可以控制验证的发生方式和时间.

猜你在找的asp.Net相关文章