Реализация уникального ограничения с помощью ValidateEntity приводит к ошибке «Указанный ключ отсутствует в словаре» - PullRequest
1 голос
/ 09 августа 2011

В поисках попыток реализовать уникальные проверки ключей для моей базы данных с помощью EF CodeFirst / Mvc3 я натолкнулся на этот пост http://blogs.msdn.com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspx, в котором приведен пример того, как это сделать, используя IValidateObject для моей объектной модели. :

public class Category : IValidatableObject
{
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var testContext = (TestContext)validationContext.Items["Context"];

        if (testContext.Categories.Any(
            c => c.CategoryName == CategoryName && c.CategoryID != CategoryID))
        {
            yield return new ValidationResult("A category with the same name already exists!", new[] { "CategoryName" });
        }

        yield break;
    }
}

и переопределение DbEntityValidationResult ValidateEntity:

public class TestContext : DbContext
{
    public DbSet<Test.Models.Category> Categories { get; set; }

    protected override DbEntityValidationResult ValidateEntity( DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        var myItems = new Dictionary<object, object>();
        myItems.Add("Context", this);
        return base.ValidateEntity(entityEntry, myItems);
    }

}

И действие на контроллере

[HttpPost]
public ActionResult Create(Category category)
{
    if (ModelState.IsValid) {
        categoryRepository.InsertOrUpdate(category);
        categoryRepository.Save();
        return RedirectToAction("Index");
    } else {
        return View();
    }
}

Но я получаю ошибку: "The given key was not present in the dictionary." для строки

var testContext = (TestContext)validationContext.Items["Context"];

Похоже, что вызывается Validate для объекта, который обращается к «Context» до его установки в коде переопределения ValidateEntity.

Сначала я подумал, что это мог быть ModelState. Недействительный запуск проверки слишком рано, но это не так.

Кто-нибудь знает, что мне здесь не хватает или что я делаю не так? Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 09 августа 2011

Model.IsValid определенно вызывает это слишком рано и, возможно, что-то еще.IValidatableObject - это глобальный интерфейс, используемый как MVC, так и EF, но ваш метод в DbContext вызывается только тогда, когда вы вызываете SaveChanges в контексте, поэтому любое использование IValidatableObject до вызова SaveChanges приведет к исключению.Вы должны использовать другой подход, если вы хотите проверить свою сущность таким образом.Например, сохранить контекст в HttpContext.Items - вы можете создать пользовательский фильтр действий, создать экземпляр и сохранить контекст перед вызовом операции и утилизировать его после вызова операции - надеюсь, он охватит все проблемы.

0 голосов
/ 02 июля 2012

Я столкнулся с той же проблемой ... Затем, после долгих поисков, я наконец нашел это:

Упражнение 3: использование пользовательской проверки IValidatableObject

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    MusicStoreEntities storeDB = new MusicStoreEntities();

    if (storeDB.Albums.Any(
                       a => a.Title.Trim().ToUpper() == this.Title.Trim().ToUpper() &&
                       a.ArtistId == (int)this.ArtistId))
    {
        yield return new ValidationResult("Existing Album", new string[] { "Title" });
    }
}

Как вы видите в их примере, они создают новый Context, и поэтому нет необходимости в validationContext.Items["Context"];. При этом мы больше не получим эту ошибку.

...