Entity Framework со строго типизированным MVC - PullRequest
12 голосов
/ 22 мая 2009

Я использую ASP.NET MVC и ADO.NET Entity Framework вместе.

Я хочу, чтобы мои представления и контроллеры были строго напечатаны.

Но как мне справиться с ассоциациями сущностей?

Вот простой пример:

Человек имеет один отдел. В отделе ноль или более человек.

Entity Data Model of Person and Department entities

Мой контроллер передает экземпляр объекта Person и коллекцию всех объектов Department в представление.

public class PersonController : Controller
{
    ...

    //
    // GET: /Person/Create

    public ActionResult Create()
    {
        Person Model = new Person();
        Model.Id = Guid.NewGuid();
        ViewData["Departments"] = db.Department;
        return View(Model);
    } 
    ...
}

В My View есть список DropDownList "Department" со всеми отделами в качестве параметров.

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Id">Id:</label>
            <%= Html.TextBox("Id") %>
            <%= Html.ValidationMessage("Id", "*") %>
        </p>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %>
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Department">Family:</label>
            <%= Html.DropDownList("Department", new SelectList((IEnumerable)ViewData["Departments"], "Id", "Name"))%>
            <%= Html.ValidationMessage("Department", "*")%>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

Но объект Person, отправленный на контроллер, не имеет отдела и не работает!

public class PersonController : Controller
{
    ...

    //
    // POST: /Person/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person Model)
    {
        try
        {
            db.AddToPerson(Model);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
    ...
}

Почему выбранный отдел из "Отдела" из DropDownList автоматически не добавляется в модель Person?

Как использовать ADO.NET Entity Framework и ASP.NET MVC со строго типизированными представлениями и контроллерами?

Ответы [ 3 ]

5 голосов
/ 22 мая 2009

Я постараюсь помочь вам со стороны MVC, так как именно в этом проблема, я полагаю

В методе Create () вы создаете объект Person и список отделов из базы данных, затем оба объекта передаются в представление. Представление берет данные из списка Department и использует их для отображения HTML-формы, используя только Id и Name.

На следующем шаге форма отправляется на сервер в виде набора пар ключ-значение (стандартное POST). Механизм маршрутизации берет запрошенный URL-адрес из атрибута действия и преобразует его в действие PersonController.Create (Person Model). Аргументом этого метода является Person, поэтому механизм связывания данных создает новый экземпляр класса Person и пытается сопоставить входящие данные со свойствами Person. В случае Department входящим значением является Id отдела (потому что это то, что вы задали в качестве элемента значения для DropDownList), в то время как свойство Department в классе Person, вероятно, относится к типу Department. Это несоответствие, поэтому оно не может заполнить свойство и остается пустым.

Как видите, это не ограничение DropDownList, проблема в том, что вы не можете передать все данные Отдела в DropDownList и создать его заново во время сохранения (как с Person) из-за характера запроса POST и именно поэтому DropDownList принимает только два значения из каждого отдела (значение и имя).

Мое обычное решение: так как обычно мои модели не являются теми же классами, что и мои бизнес-объекты, я делаю это, имея два свойства в модели: получить только свойство IEnumerable и другое свойство DepartmentId (get / set). Тогда я использую это так:

<%= Html.DropDownList("DepartmentId", Model.Departments) %>

Затем в действии сохранения я извлекаю Department из базы данных с помощью DepartmentId, назначаю его Person и сохраняю.

В вашем случае (модели являются бизнес-объектами), я бы, вероятно, не пытался автоматически привязать модель Department к Person, а просто взял Id и сделал бы это сам.

Это всего лишь предположение (я не специалист по EF), но я думаю, что у вас здесь может быть другая проблема: если db - это поле в Controller, и оно создается заново при каждом запросе, это может быть ненужным накладные расходы. Я надеюсь, что он не открывает соединение с БД каждый раз, пожалуйста, проверьте его.

Надеюсь, это поможет

3 голосов
/ 31 декабря 2009

Я использую ViewModel (ознакомьтесь с руководством по NerdDinner, ссылки внизу).

Во-первых, вам нужно подделать ограничение внешнего ключа, расширив вашу модель в частичном:

public partial class Person
{
  public int DepartmentId
  {
    get
    {
      if(this.DepartmentsReference.EntityKey == null) return 0;
      else 
        return (int)this.DepartmentsReference.EntityKey.EntityKeyValues[0].Value;
    }
    set
    {
      this.DepartmentsReference.EntityKey = 
          new EntityKey("YourEntities.DepartmentSet", "Id", value);
    }
  }
}

Во-вторых, создайте ViewModel:

public class PersonFormViewModel
{
  public SelectList Departments { get; set: }
  public Person Pers { get; set; }

  public PersonFormViewModel(Person p, List<Department> departments)
  {
    this.Pers = p;
    this.Departments = new SelectList(departments, "Id", "Name", p.DepartmentId);
  }
}

В-третьих, действие контроллера (сокращенный пример создания):

public ActionResult Create()
{
  YourEntities entities = new YourEntities();
  List<Department> departments = entities.DepartmentSet.ToList();
  PersonFormViewModel viewModel = 
    new PersonFormViewModel(new Person(), departments);
  return View(modelView);
}    

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="Id")]Person personToCreate
{
  YourEntities entities = new YourEntities(); // Probably not instantiated here
  entities.AddToPersonSet(personToCreate);
  entities.SaveChanges();
  redirectToAction("Index");
}

В-четвертых, фрагмент кода:

<p>
  <label for="Name">Name:</label>
  <%= Html.TextBox("Name", Model.Pers.Name) %>
  <%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
  <label for="DepartmentId">Family:</label>
  <%= Html.DropDownList("DepartmentId", Model.Departments)%>
  <%= Html.ValidationMessage("DepartmentId", "*")%>
</p>

Ссылка:

2 голосов
/ 22 мая 2009

Я не обнаружил, что готовый помощник DropDownList очень хорошо работает с привязкой модели. Мне всегда приходится извлекать значение DropDownList из ViewData и сопоставлять это значение вручную в моем контроллере до принятия изменений в хранилище или в базу данных.

Большую часть времени я использую DropDownList для отображения опций для отношений с пользовательским типом (таких как «Отделы для человека»). MVC не может знать, как отобразить объект просто на основе значения выбранного элемента в списке. Скорее, вам нужно взять эту сущность, используя выбранное значение, и отобразить ее самостоятельно. Я не знаю, в этом ли проблема, и я не пробовал привязывать модель к модели с простыми типами в качестве опций (например, количество продуктов для покупки или что-то подобное), но мне было бы любопытно узнать больше об этой конкретной проблеме и о том, как другие управляют связыванием модели с помощью выпадающих списков.

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