编辑模型时忽略检查特定属性的重复项

时间:2014-04-30 07:22:28

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

我有一个用户添加"标识"不需要复制的财产。 (与DB Id不同)。

我已将以下方法添加到我的ViewModel中:

 public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            GearContext db = new GearContext();
            if (db.Items.Where(p => p.Identification == this.Identification).Count() > 0)
            {
                yield return new ValidationResult("Identification already in use, please chose a different one. ", new[] { "Identification" });
            }
        }

问题在于这阻止我编辑我的模型。我希望这个验证只在创建新条目时发生,而不是在编辑时发生。

我在控制器中尝试了以下类型的编辑:

if (ModelState.IsValid)
            {
                var item = db.Items.Find(viewModel.ItemId);
                Mapper.Map<ItemViewModel, Item>(viewModel, item);
                if (TryUpdateModel(item, null, null, new string[] { "Identification" }))
                {
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }


            }

也试过没有&#34; TryUpdateModel&#34;在所有(简单的viewmodel =&gt;模型和db.save)。

我考虑在我的数据库上下文中实现验证方法,而只在item.State == EntityState.Added上运行它,但我相信我无法访问那里编辑过的模型属性。

2 个答案:

答案 0 :(得分:1)

要防止正在编辑的项目触发验证错误,请在您使用的查询中添加对ID的检查。即改变这一行:

if (db.Items.Where(p => p.Identification == this.Identification).Count() > 0)

到此:

if (db.Items.Where(p => p.ID != this.ID && p.Identification == this.Identification).Count() > 0)

另外,我还要将.Count() > 0更改为.Any(),以便查询不会超过1条记录

另外,我真的认为你应该考虑在DbContext中实现这一点,以避免使用DbContext污染Model类。这里描述了这样做的方法:https://stackoverflow.com/a/18736484/150342

答案 1 :(得分:0)

您可以做的是更改IValidatableObject方法以使其成为集合。像这样的东西

public ICollection<IValidatableObject> Validations { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var valid = Enumerable.Empty<ValidationResult>();

    if (Validations != null)
    {
        valid = Validations.Aggregate(valid, (current, validate) => current.Concat(validate.Validate(validationContext)));
    }
    return valid;
}

您现在可以将验证附加到IValidatableObject接口将调用的Validations集合。添加时,您可以添加重复检查。编辑时,请将其关闭或添加其他验证检查。

据说我确实认为重复的关键字段应该是数据库的责任而不是验证方法。即使进行此检查,仍有可能存在重复。在将数据发送到SQL之前执行IValidatableObject检查。因此,您可以让两个具有相同键的实体同时进行此检查,并且两者都将通过,并且两者都将添加到SQL中。如果你真的想确保你需要覆盖dbcontexts savechanges方法

public override int SaveChanges()
{
    var results = base.SaveChanges();

    // Run validation again for adds
    PostValidation();

    return results;
}

只要您处于事务中它尚未提交,您现在可以检查SQL是否有重复密钥,如果是,则抛出错误并回滚事务。