Как проверить модель Entity Framework 4 с использованием метаданных, когда проверка свойства зависит от значения другого свойства? - PullRequest
0 голосов
/ 17 июля 2011

У меня есть модель Entity Framework, к которой я пытаюсь добавить валидацию, но я нашел себя в некоторой ловушке 22. Здесь 1001 *

У меня есть частичный класс, связанный с моделью, сгенерированной сущностью, в отдельном файле, который выглядит следующим образом ...

[MetadataType(typeof(cmsNodeMetadata))]
public partial class cmsNode : IDataErrorInfo
{  
    ... Code ....


    #region IDataErrorInfo

    private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();
    private readonly Entities _db = new Entities();
    public string this[string columnName]
    {
        get
        {
            if (_errors.ContainsKey(columnName))
                return _errors[columnName];
            return string.Empty;
        }
    }

    public string Error { get; private set; }

    partial void OnNameChanging(string value)
    {
        var valueIsUnique = (from n in _db.cmsNodes
                             where n.ParentId == ParentId
                                && n.Name.Trim().ToLower() == value.Trim().ToLower()
                             select n.Name).Count() == 0;

        if (!valueIsUnique)
        {
            _errors.Add("Name", "The name must be unique");
        }
    }

    #endregion  

}

... и я добавил проверку в отдельный класс, который прекрасно работает.

public class cmsNodeMetadata
{
    [StringLength(150), Required]
    [Display(Name = "Name")]
    public string Name;
}

Я работаю с MVC 3, и мой контроллер, использующий этот класс, выглядит следующим образом ...

[HttpPost]
public ActionResult Edit(cmsNode cmsnode)
{
    if (ModelState.IsValid)
    {
        var obj = _db.cmsNodes.Single(c => c.Id == cmsnode.Id);
        obj.Name = cmsnode.Name;
        obj.Alias = cmsnode.Name.Slugify(150);
        _db.SaveChanges();
        return Content(Boolean.TrueString);
    }
    return Content("Please review your form");
}

Мое мнение, использующее этот класс, выглядит следующим образом ...

@model Project.com.Admin.Models.cmsNode

@using (Ajax.BeginForm("Create", "Node", null, new AjaxOptions
{
    UpdateTargetId = "create-message",
    InsertionMode = InsertionMode.Replace,
    HttpMethod = "POST",
    OnSuccess = "createSuccess"
}, new { @id = "createNodeForm" }))
{
    @Html.ValidationSummary(true)
    <div id="create-message" class="error invisible"></div>
    <fieldset>
        <legend>Create New Navigation Tree Node</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        @Html.HiddenFor(model => model.ParentId)
        @Html.HiddenFor(model => model.Alias)
    </fieldset>
}

Хорошо, вот в чем проблема. Мне нужно добавить некоторую пользовательскую проверку в этот класс (cmsNode), который проверяет, чтобы убедиться, что имя еще не занято ни одним другим узлом с таким же ParentId.

Для этого мне нужно получить дескриптор члена экземпляра с именем ParentId. К сожалению, я не могу понять, как получить дескриптор экземпляра, который я проверяю, из класса cmsNodeMetadata.

Поэтому я попытался изменить свой подход, переопределив метод onChanging для свойства Name в моем классе cmsNode и добавив туда проверку, но это вызвало еще одну проблему. Хотя я могу проверить свойство name с помощью переопределенного метода проверки, я получаю исключения, когда имя возвращается неустановленным из представления, потому что моя модель сущности не исключает нулевые значения для свойства Name, и я не могу его перехватить, потому что содержимое представления преобразуется в тип модели во входном параметре моего контроллера.

Затем я попытался использовать оба метода, кроме метода проверки MetadatatType и onChanging, но метод onChanging игнорируется.

Я понимаю, что мог бы решить эту проблему следующим образом:

  • Я мог бы изменить тип возвращаемого значения контроллера на коллекцию FormCollection, объект dto, или напрямую определить входные свойства и использовать, а затем создать объект в контроллере после того, как я проверю нулевое значение, которое вполне подходит.

Мне просто интересно, я что-то упустил? Есть ли способ проверить свойство и проверить наличие повторяющихся имен с помощью ValidationAttributes? Могу ли я предотвратить возвращение Nulls из моего поля зрения? Почему метод onChanging в платформе сущностей не имеет опции Cancel для предотвращения установки элемента, если проверка не работает? Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 17 июля 2011

Перекрестная проверка сущности не является частью самой сущности, поскольку она не входит в ее обязанности.Из-за этого вы не должны ожидать, что эта сущность или любой валидатор, помещенный в эту сущность, выполнит эту валидацию.Другая причина, по которой ваша организация не должна выполнять эту проверку, заключается в том, что для создания запроса ей необходим контекст, а сущность (POCO) не должна зависеть от контекста.

Кто отвечает за эту проверку?В зависимости от архитектуры вашего приложения, либо отдельный метод, который будет вызываться внутри вашего блока IsValid, как только сам объект будет действительным.Этот метод будет использовать EF и запрашивать, если такое же имя существует.Если вы близки к дизайну, управляемому доменом, проверка должна проводиться в родительском элементе, который будет проверять, что ни один из его дочерних элементов не имеет такого же имени (это означает, что он будет загружать дочерние элементы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...