2014-01-16 2 views
1

У меня возникли проблемы с пониманием правильного способа создания моделей представления и сохранения этой информации в базе данных с помощью Entity Framework, и я не могу найти информацию, которую я ищу потому что, пожалуйста, простите меня, если я упустил это.Просмотреть виртуальные свойства модели и выпадающие списки

Я наткнулся на это сообщение here, и он, кажется, задает тот же вопрос, но не получает ответа.

Мои основные вопросы,

Для целей редактирования, если у меня есть ProductModel model, который имеет Warranty model отношения, я должен использовать virtual property Warranty в модели представления или я должен использовать int WarrantyId?

Если я должен использовать виртуальную собственность, почему не этот код сохранить Warranty правильно?

Нужно ли явно указывать или заполнять гарантию на обновление?

Пожалуйста, не заполняйте мое редактируемое представление и не выбирайте списки по назначению.

My (упрощенный) код установки следующим образом:

Модель:

public int ModelId{ get; set; } 

    public int ModelNumber { get; set; } 

    public virtual Warranty Warranty { get; set;} 

вид Модель:

public int ModelId { get; set; } 

    [Required(ErrorMessage = "Model Number required")] 
    [StringLength(25, ErrorMessage = "Must be under 25 characters")] 
    [Display(Name="Model Number")] 
    public string ModelNumber { get; set; } 

    //related objects and necesary properties 
    public virtual Warranty Warranty { get; set; } 

    public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; } 

Controller (ГЭТ):

public ActionResult Edit(int? id) 
    { 
     //check the id 
     if (id == null) 
     { 
      return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
     } 

     //get the model and make sure the object is populated 
     var model = _modelService.GetModel(id.Value); 
     if (model == null) 
     { 
      return HttpNotFound(); 
     } 

     //pass our entity (db) model to our view model 
     var editModelModel = new EditModelModel(); 
     editModelModel.InjectFrom(model); 

     //warranty select list 
     editModelModel.WarrantySelectListItems = WarrantySelectList(editModelModel.Warranty.WarrantyId); 

     //option multi select list 
     editModelModel.OptionSelectListItems = OptionSelectList(); 

     return View(editModelModel); 
    } 

контроллер (POST) (незавершенное производство):

[HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Edit(EditModelModel editModelModel) 
    { 
     if (!ModelState.IsValid) 
     { 
      return View(editModelModel); 
     } 

     var modelEntity = new Model(); 
     modelEntity.InjectFrom(editModelModel); 

     _modelService.Update(modelEntity); 
     _unitOfWork.Save(); 

     return RedirectToAction("Index"); 
    } 

View (упрощенно):

<div class="form-group"> 
     @Html.Label("Warranty", new { @class = "control-label col-md-2" }) 
     <div class="col-md-10"> 
      @Html.DropDownListFor(x => x.Warranty.WarrantyId, Model.WarrantySelectListItems, "--Select--") 
      @Html.ValidationMessageFor(model => model.Warranty.WarrantyId) 
     </div> 
    </div> 

Опять же, я просто хочу знать, как правильно/лучший способ настроить эти ViewModels и модель, так что EF делает так много работы, как это возможно , Мне кажется, что если мне нужно создать поле WarrantyId, я делаю что-то неправильно, но, возможно, это не так.

Заранее спасибо. Любое понимание/помощь приветствуется.

ответ

4

Для целей редактирования, если у меня есть модель, которая имеет ProductModel модель отношений с гарантии, я должен быть с помощью виртуальной собственности гарантии в модели представления или я должен использовать Int WarrantyId?

Вы не используете virtual ключевое слово для свойства вашего ViewModel, потому что ViewModel не имеет ничего общего с Entity Framework. Причина использования ключевого слова virtual заключается в том, чтобы разрешить ленивую загрузку в Entity Framework. В вашем случае, если вы добавляете virtual ключевое слово для гарантии навигации свойства в классе продукта POCO, вы можете получить доступ к свойству гарантии, как показано ниже:

Model.Warranty.WarrantyId 

И причина этого не сохранить информацию о гарантии в ваша база данных - это то, что вам необходимо определить свойство внешнего ключа гарантии в классе Product.

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

public class Product 
    { 
     public int ModelId { get; set; } 
     public int ModelNumber { get; set; } 
     public int WarrantyId {get;set;} 

     [ForeignKey("WarrantyId ")] 
     public virtual Warranty Warranty { get; set; } 
    } 

Тогда ваш ViewModel:

public class MyViewModel 
    { 
     public Product Product { get; set; } 
     public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; } 
    } 

Наконец ваш взгляд

@model MyViewModel 

    @Html.DropDownList("Product.Warranty.WarrantyId", Model.WarrantySelectListItems, "--Select--") 
    @Html.ValidationMessageFor("Product.Warranty.WarrantyId") 

Конечно, вам необходимо изменить свои методы действий для соответствия ViewModel.

+0

Хотя несколько других ответов были очень хорошими, я принимаю это как ответ на этот вопрос, потому что он отвечает на заданные вопросы и дает примеры того, как решить мой вопрос модели-viewmodel в пределах заданных границ исходного вопроса. Кроме того, он имеет самые высокие голоса. –

0

У вас должна быть встроенная гарантия в вашей модели. Чем на ваш взгляд

@Html.DropDownListFor(x => x.WarrantyId, Model.WarrantySelectListItems, "--Select--") 

В контроллере (POST) принимать WarrantyId (выбирается из выпадающего списка) и найти объект из базы данных (вар гарантия = db.Warranties.Where (ш => w.WarrantyId == editModelModel.WarrantyId или что-то в этом роде), и этот объект присваивает modelEntity.

1

То, что вы имеете дело с, безусловно, свойства навигации (виртуальные свойства на вашей модели классов), и это делает хорошую работу, объясняя им:

http://msdn.microsoft.com/en-us/data/jj713564.aspx

Хитрость в определении них действительно в том, как вы настроили свой DbContext для базы данных. Официальный документ об этом здесь:

http://msdn.microsoft.com/en-us/data/jj591620

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

Часть MVC является отдельной заботой, и в идеале вы должны относиться к ней как таковой. Код контроллера должен делегировать реальную «работу» другим классам. Единица шаблона работы, если вы решите использовать ее, на самом деле не нужна, пока вы не столкнетесь с ситуациями, когда у вас есть большой кусок материала, который может сохраняться/редактироваться во многих таблицах или наборах объектов, с идеей, что вы можете хочу, чтобы все это потерпело неудачу или преуспело в целом. Если вы просто справляетесь с простой сохранностью отдельных объектов, не затрудняйте ее с помощью шаблона работы.

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

+0

Спасибо, Джефф, за информацию. Определенно поможет мне! –

2

Для целей редактирования Если у меня есть модель ProductModel, которая имеет отношение к модели гарантии, следует ли использовать виртуальную собственность Warranty в модели представления или использовать функцию int WarrantyId?

Вы не должны использовать виртуальные объекты в своих моделях просмотра. Модель просмотра просто представляет собой фрагмент данных, который необходим для отображения представления. Поскольку вы сопоставляете эту модель с вашими сущностями, вам не нужно отмечать что-либо как виртуальное. См. this answer, если вы хотите знать, что делает virtual в отношении Entity Framework.

Также вы должны включать информацию, необходимую для визуализации этого вида. Так что, если вам просто нужен WarrantyId в представлении, тогда включите его.

Поскольку вы также привязываетесь к модели с той же моделью просмотра в своем действии POST, вы должны быть очень конкретным относительно того, что вы хотите представить своей модели представления, иначе вы оставите себя открытым для over-posting attack.

Мне кажется, что если мне нужно создать поле WarrantyId, я делаю что-то неправильно, но, возможно, это не так.

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

Однако, имея отдельные модели просмотра для ваших просмотров и применяя правила проверки на сами модели представлений, теперь у вас могут быть разные требования к валидации в ваших представлениях. Например:

public class ViewAViewModel 
{ 
    [Required] 
    public int WarrantyId { get; set; } 
} 

public class ViewBViewModel 
{ 
    // No longer required. 
    public int WarrantyId { get; set; } 
} 

Если бы вы включили Warranty непосредственно в обоих этих взглядов, вы застряли с одним набором правил проверки.

Это в стороне, я задаюсь вопросом, почему у вас есть это на вашей модели (который я предполагаю, является юридическим лицом):

public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; } 

Это не принадлежит здесь. Это подробная информация о презентации, и она не должна существовать в ваших бизнес-объектах. Он должен существовать на вашей модели представления.

+0

На самом деле, эта часть, о которой вы думаете, является опечаткой с моей стороны. Список выбора находится в режиме просмотра. Я отредактировал это, чтобы отразить это. –

+0

@MikeMcCoy. Тогда все в порядке, так как в этом оно и есть. –

+1

Спасибо за ваш ответ, это было очень полезно –

1

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

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

Кроме того, ViewModels позволяют протестировать пользовательский интерфейс без наличия базы данных и без этой сложности. Вы действительно устраняете проблемы пользовательского интерфейса и моделирование данных.

Обычно я вообще не использую модели в пользовательском интерфейсе, всегда через ViewModel, что упрощает мою жизнь в конце, даже если это больше работает в первую очередь.

Итак, давайте сделаем пару изменений.

View Model (Переименован к EditViewModel для ясности):

public int ModelId { get; set; } 

// Removed for clarity, include needed properties in the UI 

public int WarrantyId { get; set; } 

public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; } 

Controller (ГЭТ):

public ActionResult Edit(int? id) 
{ 
    //check the id 
    if (id == null) 
    { 
     return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
    } 

    //get the model and make sure the object is populated 
    var model = _modelService.GetModel(id.Value); 
    if (model == null) 
    { 
     return HttpNotFound(); 
    } 

    //pass our entity (db) model to our view model 
    var editViewModel = new EditViewModel(); 
    editViewModel.InjectFrom(model); 

    // You could instead create a custom injection like FlatLoopValueInjection 
    // That would flatten and remove duplicates from 
    // Model.Warranty.WarrantyId to ViewModel.WarrantyId 
    editViewModel.WarrantyId = model.Warranty.Id; 

    //warranty select list 
    editViewModel.WarrantySelectListItems = WarrantySelectList(editViewModel.WarrantyId); 

    return View(editViewModel); 
} 

Пользовательские Injection Flatten - FlatLoopValueInjection:

http://valueinjecter.codeplex.com/wikipage?title=flattening&referringTitle=Home

Controller (POST):

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Edit(EditViewModel editViewModel) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(editViewModel); 
    } 

    // You need to reconstruct the model itself, there are faster ways but I wanted 
    // to showcase the logic behind it 
    // I didn't do any null check or anything to simplify 

    // Load the model used from the database 
    var modelEntity = _modelService.GetModel(editViewModel.ModelId); 

    // You can do an InjectFrom for the other properties you need 
    // with custom Injection to unflatten 
    modelEntity.InjectFrom(editViewModel); 

    // Load the selected warranty from the database 
    var warrantyEntity = _warrantyService.GetWarranty(editViewModel.WarrantyId); 

    // Update the warranty of the model with the one loaded 
    modelEntity.Warranty = warrantyEntity; 

    _modelService.Update(modelEntity); 

    _unitOfWork.Save(); 

    return RedirectToAction("Index"); 
} 

Теперь на ваш взгляд:

<div class="form-group"> 
    @Html.Label("Warranty", new { @class = "control-label col-md-2" }) 
    <div class="col-md-10"> 
     @Html.DropDownListFor(x => x.WarrantyId, Model.WarrantySelectListItems, "--Select--") 
     @Html.ValidationMessageFor(model => model.WarrantyId) 
    </div> 
</div> 

В качестве примечания, в моделях и просматривать модели, вы должны попробовать, чтобы никогда не повторять префиксы в именах, как:

  • модели. ModelID
  • Warranty.WarrantyId

Если это не внешний ключ или значение:

  • Model.WarrantyId

Почему? Это намного проще, чтобы сгладить/unflatten их по соглашению с InjectFrom:

Model.Warranty.Id => (flatten) => Model.WarrantyId => (unflatten) => Model.Warranty.Id 

Кроме того, это лучшая практика. Название модели/таблицы уже указывает тип сущности, не нужно его повторять.

Смежные вопросы