当运行一个实体重复检查 [英] Where to run a duplicate check for an entity

查看:395
本文介绍了当运行一个实体重复检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在寻找建议最好的地方使用实体框架code-首先,在MVC应用程序时,将验证逻辑,如重复检查的实体。

I'm looking for advice on the "best" place to put validation logic, such as a duplicate check for an entity, when using Entity Framework Code-First, in an MVC application.

要使用一个简单的例子:

To use a simple example:

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

该规则是,在名称字段中必须是唯一的。

The rule is that the "Name" field must be unique.

在我的添加的新JobRole,很容易运行,该名称不存在工作角色仓库进行检查。

When I add a new JobRole, it is easy to run a check in the Job Role Repository that the Name doesn't already exist.

但是,如果用户的编辑的现有JobRole,一不小心将名称设置为某个已经存在,我该怎么检查呢?

But if a user edits an existing JobRole, and accidentally sets the Name to one that already exists, how can I check this?

问题是,有没有需要是对信息库更新的方法,因为工作角色实体会自动检测变化,所以没有尝试保存之前做此项检查一个合乎逻辑的地方。

The issue is that there doesn't need to be an "update" method on the Repository, as the Job Role Entity will automatically detect changes, so there isn't a logical place to do this check before attempting to save.

我已经考虑了两个方案至今:

I have considered two options so far:

  1. 在覆盖上的DbContext的ValidateEntry方法,然后当JobRole实体被保存EntityState.Modified,运行重复检查即可。
  2. 创建某种形式的重复检查服务,从控制器调用,在尝试保存之前。

无论是看起来真的很理想。使用ValidateEntry显得相当晚(之前保存)和难以测试。使用服务离开,有人忘了从控制器调用它,通过让重复数据的可能性。

Neither really seems ideal. Using ValidateEntry seems rather late (just before save) and hard to test. Using a Service leaves the possibility that someone forgets to call it from a Controller, letting duplicate data through.

有没有更好的办法?

推荐答案

您的问题,执行validateEntity似乎是在验证发生在SaveChanges的,这是太晚了你。但在实体框架5.0,你可以调用验证前面,如果你想使用<一个href="http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.getvalidationerrors%28v=vs.103%29.aspx"相对=nofollow> DbContext.GetValidationErrors 的。当然,你也可以只叫<一href="http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.validateentity%28v=vs.103%29.aspx"相对=nofollow> DbContext.ValidateEntity 直接。这就是我如何做到这一点:

Your problem with ValidateEntity appears to be that the validation occurs on SaveChanges and this is too late for you. But in Entity Framework 5.0 you can call the validation earlier if you wish using DbContext.GetValidationErrors. And of course you could also just call DbContext.ValidateEntity directly. This is how I do it:

  1. 覆盖上的执行validateEntity 方法的DbContext

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"));
}

  • 嵌入 Context.SaveChanges 在尝试捕捉并创建一个方法来访问 Context.GetValidationErrors( )。这是我的的UnitOfWork 类:

  • Embed Context.SaveChanges in a try catch and create a method to access Context.GetValidationErrors(). This is in my UnitOfWork class:

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

  • 在我的控制器,通话 GetValidationErrors()添加实体上下文后,但在此之前的SaveChanges()

  • In my controller, call GetValidationErrors() after adding the entity to the context but before SaveChanges():

    [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 是这样的:

    My base repository class implements InsertOrUpdate like this:

        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使控制权负载如何以及何时验证发生。

    I still recommend adding a unique constraint to the database because that will absolutely guarantee your data integrity and provide an index that can improve the efficiency, but overriding ValidateEntry gives loads of control over how and when validation occurs.

    这篇关于当运行一个实体重复检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆