Две проверки IValidatableObject в одной сущности

Это суть проекта, при создании которого необходимо проверить, существует ли уже объект с таким именем. При редактировании необходимо, например, проверка, но имейте в виду, что старое и новое имя объекта могут совпадать. Вам также необходимо отобразить сообщение об ошибке. Для этого я использую интерфейс IValidatableObject, но не знаю, как сообщить методу Validate, что объект в данный момент редактируется или создается

3 ответа

Решение

Проблема решается с помощью метода ModelState.AddModelError (string, string) в действиях Edit и Create.

[HttpPost]
[HandleError(View="AjaxError")]
public ActionResult Edit(ProjectsViewData data)
{
    if (ModelState.IsValid)
    {
        if (!ContainsProject(data.CurrentObject.Name))
        {
            db.Projects.Attach(data.CurrentObject);
            db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
            db.SaveChanges();
            return Projects(data);
        }
        else
        {
            int projectId = (from p in db.Projects
                                where p.Name == data.CurrentObject.Name
                                select p.ProjectID).FirstOrDefault();
            if (projectId == data.CurrentObject.ProjectID)
            {
                db.Projects.Attach(data.CurrentObject);
                db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
                db.SaveChanges();
                return Projects(data);
            }
            else
            {
                ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
            }
        }
    }

    data.ObjectToEdit = data.CurrentObject;
    return Projects(data);
}

[HttpPost]
[HandleError(View = "AjaxError")]
public ActionResult Create(ProjectsViewData data)
{
    if (ModelState.IsValid)
    {
        if (!ContainsProject(data.CurrentObject.Name))
        {
            db.Projects.AddObject(data.CurrentObject);
            db.SaveChanges();
            return Projects(data);
        }
        else
        {
            ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
        }
    }

    data.ObjectToAdd = data.CurrentObject;
    return Projects(data);
}

Вспомогательный метод:

private bool ContainsProject(string projectName)
{
    if (projectName != null)
    {
        projectName = Regex.Replace(projectName.Trim(), "\\s+", " ");
        List<string> projects = new List<string>();
        var projectNames = (from p in db.Projects
                            select p.Name.Trim()).ToList();
        foreach (string p in projectNames)
        {
            projects.Add(Regex.Replace(p, "\\s+", " "));
        }
        if (projects.Contains(projectName))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

Предполагая, что вы обращаетесь, чтобы проверить, EF не может сделать для вас.
Это на самом деле сложно проверить. Вы проверяете сущность после того, как она была добавлена ​​в контекст. Он не должен проверять себя и должен учитывать другие элементы в контексте, которые еще не сохранены. Как и БД. Есть несколько 3 комбинаций плюс самопознание. Запишите запись объекта в LOCAL, когда ID пуст / новый, т.е. несколько новых вставок требуют тщательного кодирования. (Рассмотрите возможность использования временных идентификаторов)

еще не сохраненные записи должны быть в контексте

Context.Set<TPoco>().Local

и получить данные из БД и сохранить в списке временных. НО не помещайте в контекст. Или используйте ВТОРОЙ контекст.

 var matchingSet = Context.Set<TPoco>().AsNoTracking()   // not into context...
                      .Where(t=>t.field == somevalue).ToList(); 

Так что насчет логических и реальных дубликатов на БД. Логические дубликаты являются дубликатами в поле без уникального индекса, который с точки зрения бизнеса должен быть уникальным.

Если вы хотите проверить эти...

Вам нужно прочитать DB.... НО, если эти записи в настоящее время изменяются, вы НЕ МОЖЕТЕ просто поместить их в контекст. Вы бы переписали их. Но что, если значения значений логического ключа изменились? Что-то вызвало логическое дублирование записи в БД, которая может больше не быть дублированием после сохранения или наоборот. Это все еще дуп или нет?

Таким образом, вам нужно решить, как вы будете сопоставлять LOCAL с загруженными записями. Т.е. проверять LOCAL и соответствующие записи в БД и решать, что делать, если запись находится в обоих, только локальных или только в дБ. ЛОКАЛЬНО ТОЛЬКО и БД только легко.
Но в обоих случаях... Это решение вашего бизнес-процесса.

DbContext.ValidateEntity принимает IDictionary<Object, Object> items как второй параметр. Вы можете передать любые данные там, и данные, которые вы передаете, будут переданы IValidatableObject.Validate в ValidationContext.Items

Другие вопросы по тегам