Пользовательская проверка MVC 3 с моделью данных объекта - PullRequest
0 голосов
/ 12 октября 2011

Я работаю над проектом с использованием MVC3. Сначала я создал базу данных (с необходимыми ограничениями, такими как PK и FK) и добавил эту базу данных в мое веб-приложение, используя модель данных объекта ADO.NET. Кажется, все работает нормально, но я не могу сделать проверку гибкой. Вот код, чтобы прояснить мой вопрос.


Редактировать: добавлен вид + правильных моделей. Эта версия без импорта базы данных, но результаты те же.


- Модели ----

namespace CustomValidation.Models
{
    public class Person : IValidatableObject
    {   

    public int Id { get; set; }
    [Required]
    public String FirstName { get; set; }
    [Required]
    public String LastName { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (String.IsNullOrEmpty(FirstName))
        {
            var field = new[] { "FirstName" };
            yield return new ValidationResult("Firstname can't be null", field);
        }
    }
}
}



namespace CustomValidation.Models
{
    public class Address : IValidatableObject
    {

    public int Id { get; set; }
    [Required]
    public String Streetname { get; set; }
    [Required]
    public String Zipcode { get; set; }
    [Required]
    public String City { get; set; }
    [Required]
    public String Country { get; set; }
    public Person Person { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (String.IsNullOrEmpty(Streetname))
        {
            var field = new[] { "Streetname" };
            yield return new ValidationResult("Streetname can't be null", field);
        }
    }
}
}


public class MasterModel
{
    public List<Address> Addressess { get; set; }
    public Person Person { get; set; }
    }
}





namespace CustomValidation.Models
{
    public class DBEntities : DbContext
    {
    public DbSet<Person> People { get; set; }
    public DbSet<Address> Addressess { get; set; }
    }
}

---- контроллер ----

namespace CustomValidation.Controllers
{
public class HomeController : Controller
{
    public ActionResult Index()
    {
        MasterModel Model = new MasterModel();
        Model.Person = new Person();
        Model.Addressess = new List<Address>();
        Model.Addressess.Add(new Address());
        Model.Addressess.Add(new Address());
        return View(Model);
    }


    [HttpPost]
    public ActionResult Index(MasterModel Model)
    {
        DBEntities _db = new DBEntities();
        if (TryValidateModel(Model.Person))
        {
            _db.People.Add(Model.Person);
            _db.SaveChanges();
        }
        else
        {
            return View(Model);
        }

        for (int i = 0; i < Model.Addressess.Count; i++)
        {
            if (!String.IsNullOrEmpty(Model.Addressess[i].Country))
            {
                if (TryValidateModel(Model.Addressess[i]))
                {
                    Model.Addressess[i].Person = Model.Person;
                    _db.Addressess.Add(Model.Addressess[i]);
                    _db.SaveChanges();
                }
                else
                {
                    return View(Model);
                }
            }
        }
        return RedirectToAction("Index");
    }
 }

Вот мой взгляд:

@model CustomValidation.Models.MasterModel
@{
ViewBag.Title = "Index";
}

<h2>Create</h2>

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
<div class="editor-label">
@Html.LabelFor(m => Model.Person.FirstName)
@Html.EditorFor(m => Model.Person.FirstName)
</div>
<div class="editor-label">
@Html.LabelFor(m => Model.Person.LastName)
@Html.EditorFor(m => Model.Person.LastName)
</div>

</fieldset>
for (int i = 0; i < Model.Addressess.Count; i++)
{
<fieldset>
    <legend>Address</legend>

    <div class="editor-label">
        @Html.LabelFor(model => Model.Addressess[i].Streetname)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Addressess[i].Streetname)
        @Html.ValidationMessageFor(model => Model.Addressess[i].Streetname)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => Model.Addressess[i].Zipcode)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => Model.Addressess[i].Zipcode)
        @Html.ValidationMessageFor(model => Model.Addressess[i].Zipcode)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => Model.Addressess[i].City)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => Model.Addressess[i].City)
        @Html.ValidationMessageFor(model => Model.Addressess[i].City)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => Model.Addressess[i].Country)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => Model.Addressess[i].Country)
        @Html.ValidationMessageFor(model => Model.Addressess[i].Country)
    </div>

</fieldset>

}
    <p>
        <input type="submit" value="Create" />
    </p>
}

Проблема (которую я заметил при отладке чего-то подобного) заключается в том, что перед тем, как запрос попадет внутрь моего действия, MVC сначала запускает валидаторы для вашей коллекции. Поэтому, если я только заполнил Person в своей форме, проверяя Model.Person, он просто возвращает false (я думаю, из-за обязательных полей для Address), и поэтому он возвращается к моему представлению.

Мне нужен какой-то обходной путь, который позволил бы мне решить, какие экземпляры моей коллекции я хочу проверить в своем действии.

Я не смог найти никакого решения после долгого поиска в сети.

Я надеюсь, что кто-то может мне помочь.

PS. Я довольно новичок в Visual Studio и MVC 3, поэтому, пожалуйста, не обращайте на меня внимания:)

1 Ответ

2 голосов
/ 13 октября 2011

Чтобы проверить подмодели модели, возвращенной к вашему действию, вам необходимо применить TryValidateModel к конкретной подмодели и использовать перегрузку, которая включает префикс для модели. Если вы посмотрите на сгенерированный HTML-код, то увидите, что поля Person имеют префикс Person, первые поля Address имеют префикс Addressess[0], а вторые поля Address имеют префикс Addressess[1].

Кроме того, необходимо очистить все ошибки модели перед вызовом TryValidateModel (или существующие ошибки приведут к тому, что TryValidateModel вернет false).

Выполните следующие действия:

[HttpPost]
public ActionResult Index(MasterModel model)
{
    var reloadView = true;

    // clear any existing errors
    foreach (var key in ModelState.Keys)
        ModelState[key].Errors.Clear();

    if (TryValidateModel(model.Person, "Person"))   
    {   
        _db.People.Add(model.Person);   
        _db.SaveChanges();   
        reloadView = false;

        for (var i = 0; i < model.Addressess.Count(); i++)
        {
            foreach (var key in ModelState.Keys)
                ModelState[key].Errors.Clear();

            if (TryValidateModel(model.Addressess[i], "Addressess[" + i.ToString() + "]"))
            {
                **// UPDATED CODE**
                // add Person to Address model
                model.Addressess[i].Person = model.Person;

                _db.Addressess.Add(model.Addressess[i]);   
                _db.SaveChanges();   
            }
        }
    }

    if (reloadView)
    {
        // clear and re-add all errors
        foreach (var key in ModelState.Keys)
            ModelState[key].Errors.Clear();

        TryValidateModel(model);
        return View(model);
    }
    else
    {
        // go to some other view
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...