How to bind an object in a view to the controller? - c#

This may be a dumb question but I'm kind of new with the razor. I'm trying to create a dynamic form. I have a list of object of fields and show them dynamically in my page. But, when I want to save the selected value of my field for a dropdown(example), I don't know how to save the object of my foreach to my model in the controller (I can save my value with no harm).
Index.cshtml:
<div class="row">
#foreach (var buildingBlock in buildingBlocks)
{
<div class="col-sm">
<div class="card">
<div class="card-body">
<h5 class="card-title">#buildingBlock.BuildingBlockTitle</h5>
#foreach (Test.Test.Models.BuildingBlockField buildingBlockField in buildingBlockFields)
{
<div class="form-group">
<label for="companyName">Company Name</label>
//I tried that but it's not working (Obviously :))
#Html.EditorFor(model => buildingBlockField)
#Html.DropDownListFor(model => model.buildingBlockFields[0].Values, buildingBlockField.OptionDetails, "Select Contract", new { #class = "selectpicker", multiple = "multiple" })
</div>
}
</div>
</div>
</div>
}
</div>
BuildingBlockField:
public class BuildingBlockField
{
public int BuildingBlockFieldID{ get; set; }
public int BuildingBlockID { get; set; }
public List<SelectListItem>? OptionDetails { get; set; }
public string FieldTitle { get; set; }
public FieldType Type { get; set; }
public bool IsMultiple { get; set; }
public int[] Values { get; set; }
public string Value { get; set; }
}
model controller:
public class ContractInformationsModel
{
public List<BuildingBlockField> buildingBlockFields { get; set; }
}
HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.BuildingBlocks = Models.BuildingBlock.getBuildingBlocks();
ViewBag.BuildingBlockFields = Models.BuildingBlockField.getBuildingBlockFields();
return View();
}
[HttpPost]
public ActionResult generateWordContract(ContractInformationsModel contractInformations)
{
return View("Index");
}
}
I expect to find in my controller object contractInformations to find a list of buildingBlockFields with all the information and not only the value.
Thank you
Edit :
This seems to work but i have to do it for every property and hide then. Is there any other solution ?
#for (var i = 0; i < buildingBlockFields.Count(); i++){
<div class="form-group">
#Html.HiddenFor(model => model.buildingBlockFields[i].BuildingBlockFieldID, new { Value = buildingBlockFields[i].BuildingBlockFieldID })
#Html.HiddenFor(model => model.buildingBlockFields[i].FieldTitle, new { Value = buildingBlockFields[i].FieldTitle })
#Html.HiddenFor(model => model.buildingBlockFields[i].Type, new { Value = buildingBlockFields[i].Type })
#Html.DropDownListFor(model => model.buildingBlockFields[0].Values, buildingBlockFields[i].OptionDetails, "Select Contract", new { #class = "selectpicker", multiple = "multiple" })
</div>
}

Since you are passing ContractInformationsModel model to your view, which has a list of type BuildingBlockField, your html should contain the building block field ID and a "counter" that can identify indexes in that list.
#{
// declare counter
int i = 0
}
#foreach (BuildingBlockField buildingBlockField in buildingBlockFields)
{
<div class="form-group">
<label for="companyName">#buildingBlockField.FieldTitle</label>
#Html.HiddenFor(model=>model.buildingBlockFields[i].BuildingBlockFieldID)
#Html.TextBoxFor(model => model.buildingBlockFields[i].FieldTitle, new { #class = "form-control", Value = #buildingBlockField.FieldTitle })
#Html.DropDownListFor(model => model.buildingBlockFields[i].Values, buildingBlockField.OptionDetails, "Select Contract", new { #class = "selectpicker", multiple = "multiple" })
</div>
#i++
}

Related

Editing Objects and Related Objects in One View with ASP.Net MVC and Entity Frameworks

I am creating an application where a Note can be created and one to many Parts can be added to the note. (The application is for a tractor salvage yard where customers call for tractor parts). I know similar questions have been asked before. But I couldn't find anything very relevant to my situation with EF and all.
I am having a lot of difficulty with creating/editing a Note with its Parts in one view. I want to focus on editing for this question, though.
I have two simple CLR classes with a relation.
public class Note
{
public int ID { get; set; }
public string CustomerName { get; set; }
public string CustomerPhone { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public string CreatedBy { get; set; }
public string AssignedTo { get; set; }
public virtual ICollection<Part> Parts { get; set; }
}
public class Part
{
public int PartID { get; set; }
public string PartNumber { get; set; }
public string Description { get; set; }
public int NoteID { get; set; }
public virtual Note Note { get; set; }
}
And the DbContext:
public class CallNoteContext : DbContext
{
public CallNoteContext() { }
public DbSet<Note> Notes { get; set; }
public DbSet<Part> Parts { get; set; }
}
My problem is binding the data from both entities to the edit view, accessing the data in the view for editing and saving the note and and multiple parts to the database in the httppost action.
I have tried a lot of things, but after reading a lot of articles, I keep coming back to this for the controller and view. To me it seems like this should work. But obviously I am missing something.
Here is the edit and post actions from my controller.
private CallNoteContext db = new CallNoteContext();
// GET: Note/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Note note = db.Notes.Find(id);
var model = new Note()
{
CustomerName = note.CustomerName,
CustomerPhone = note.CustomerPhone,
DateCreated = note.DateCreated,
DateUpdated = note.DateUpdated,
CreatedBy = note.CreatedBy,
AssignedTo = note.AssignedTo,
Parts = note.Parts
};
if (note == null)
{
return HttpNotFound();
}
return View(model);
}
// POST: Note/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,CustomerName,CustomerPhone,DateCreated,DateUpdated,CreatedBy,AssignedTo,Parts")] Note note)
{
if (ModelState.IsValid)
{
foreach(var p in note.Parts)
{
db.Entry(p).State = EntityState.Modified;
db.SaveChanges();
}
db.Entry(note).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(note);
}
When I try to make editors for p.PartNumber and p.Description in my view below, it breaks with the exception that it can't find these properties. I have a feeling that I am doing something wrong in the "get" action of the controller. But I am having a hard time figuring out what is wrong.
By the way, IntelliSense is saying No Issues Found for the controller.
Here is my Edit view.
#model CallNote.Models.Note
<head>
<script src="~/Scripts/jquery-3.4.1.js" type="text/javascript"></script>
</head>
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.CustomerName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CustomerName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomerName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CustomerPhone, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CustomerPhone, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomerPhone, "", new { #class = "text-danger" })
</div>
</div>
#*There are editors here for all of the properties, but I didn't list them to save space.*#
#*The app always breaks when it gets to this foreach because it says it can't find p.PartNumber. What is wrong?
#foreach (var p in Model.Parts)
{
<div>
#*I also tried just using p.PartNumber, but it says p doesn't exist in current context.
#Html.EditorFor(p => p.PartNumber)
#Html.EditorFor(p => p.Description)
</div>
}
<div id="partInfo" style="display:none">
#Html.EditorFor(p => p.PartNumber)
#Html.EditorFor(p => p.Description)
</div>
<div id="btnWrapper">
<input id="btnAddPart" type="button" value="Add Part" />
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
#*The script below works, allowing you to add part editors*#
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script>
$(document).ready(function () {
$("#btnAddPart").click(function () {
var partinfo = $("#partInfo").html();
$("#partInfo").append(partinfo);
});
});
</script>
Also I am unsure if the httppost action will work. I have not been able to try it yet as I cannot get the Edit view to even load yet. So if you have any suggestions for that too, let me know.
I am just getting started with MVC, so a detailed answer would be super!
you have to include Parts in the Note
....
Note note = db.Notes
.Include(i=> i.Parts)
.FirstOrDefault(i=>i.ID==id);
if (note == null)
{
return HttpNotFound();
}
.....
and since you are using editor, replace foreach loop by for loop
#if( Model.Parts!=null && Model.Parts.Count >0)
{
#for (var i=0; i< Model.Parts.Count; i++)
{
<div id="partInfo" style="display:none">
#Html.EditorFor(model => model.Parts[i].PartNumber)
#Html.EditorFor(model => model.Parts[i].Description)
</div>
...... and so on for all properties
}
}
and remove bind from the action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Note note)
{
if (!ModelState.IsValid) return View(note);
var existedNote = db.Notes
.Include(i=> i.Parts)
.FirstOrDefault(i=>i.ID==note.ID);
if(existedNote!=null)
{
db.Entry(existedNote).CurrentValues.SetValues(note);
if(note.Parts!=null && note.Parts.Count > 0)
{
foreach( var part in note.Parts)
{
var existingPart = existingNote.Parts.FirstOrDefault(p => p.PartID == part.PartID);
if (existingPart == null)
{
existingNote.Parts.Add(part);
}
else
{
context.Entry(existingPart).CurrentValues.SetValues(part);
}
}
}
db.SaveChanges();
}
return RedirectToAction("Index");
}
return View(note);
}
````

mvc multiple models in view

I am making an MVC application. I am creating a View that uses a ViewModel and also use database entities in this view passed by the controller.
Controller:
public ActionResult AddGroup(AddGroupViewModel model)
{
ClassDeclarationsDBEntities1 entities=new ClassDeclarationsDBEntities1();
return View(entities.Subjects.ToList());
}
ViewModel:
public class AddGroupViewModel
{
[Required]
[Display(Name = "Subject")]
public string subject_name { get; set; }
[Required]
[Display(Name = "Number of Groups")]
public int qty { get; set; }
}
And finally my view:
#model List<ClassDeclarationsThsesis.Classes.Subject>
#model ClassDeclarationsThsesis.Models.AddGroupViewModel
#{
ViewBag.Title = "Add Groups";
}
<h2>Add Groups to subjects</h2>
#using (Html.BeginForm("AddGroup", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create new groups.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#{
List<SelectListItem> listItems1 = new List<SelectListItem>();
}
#foreach (var subject in Model)
{
listItems1.Add(new SelectListItem
{
Text = subject.name,
Value = subject.name,
Selected = true
});
}
#Html.LabelFor(m => m.subject_name, new {#class = "col-md-2 control-label"})
<div class="col-md-10">
#Html.DropDownListFor(m => m.subject_name, listItems1, new {#class = "form-control"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.qty, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.qty, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
As you see, I am trying to use two models in my view. But gives an exception (well how to distinguish them). How do I combine those two models in a view?
Edit:
So I did what suggested in answer, but now I get such exception:
{"The class 'ClassDeclarationsThsesis.Models.Subject' has no parameterless constructor."}
The class looks like this:
namespace ClassDeclarationsThsesis.Models
{
using System;
using System.Collections.Generic;
public partial class Subject
{
private int v;
private int userid;
public Subject(int v, int userid, string name)
{
this.class_id = v;
this.user_id = userid;
this.name = name;
}
public int class_id { get; set; }
public int user_id { get; set; }
public string name { get; set; }
public virtual Group Group { get; set; }
public virtual Subjects_Users Subjects_Users { get; set; }
public virtual Task Task { get; set; }
}
}
How do I solve it?
Since you already have a view model, I'd use that:
#model ClassDeclarationsThsesis.Models.AddGroupViewModel
And simply add a property to that view model for the collection you also want to use:
public class AddGroupViewModel
{
[Required]
[Display(Name = "Subject")]
public string subject_name { get; set; }
[Required]
[Display(Name = "Number of Groups")]
public int qty { get; set; }
public List<Subject> Subjects { get; set; }
}
Then simply create an instance of that from your controller to send to the view:
var entities = new ClassDeclarationsDBEntities1();
var model = new AddGroupViewModel();
model.Subjects = entities.Subjects.ToList();
// set your other properties too?
return View(model);
Then in the view simply refer to the property on the Model instead of the model itself when you need that collection:
#foreach (var subject in Model.Subjects)
Basically, while you can use only one type for your model (since there's only one Model property available to the view in the framework), that type can be anything you like, even a custom view model type that you define.

MVC Razor EditorFor Last Object in List

I'm trying to display EditorFor for the last child Object in an collection. Below are the POCOs for the Order (Parent) and Hold (child collection):
public class Order
{
public int ID {get;set;}
public string Name {get;set;}
....
public virtual List<Hold> Holds { get; set; }
}
public class Hold
{
public int ID { get; set; }
public int OrderID { get; set; }
public virtual Order Order { get; set; }
public DateTime? When { get; set; }
public string Reason { get; set; }
}
Here's my attempt at creating an Order view that shows an Order and the last Hold if there is one present. I've commented out the last Hold attempt that doesn't work.
#model Order
#using (Html.BeginForm("Update", "Order", FormMethod.Post, new {}))
{
<div class="form-group row">
#Html.LabelFor(x => x.Name, new { #class = "col-xs-2" })
<div class="col-xs-10">
#Html.EditorFor(x => x.Name, new { #class = "form-control"})
</div>
</div>
<div class="form-group row">
<label class="col-xs-2">When</label>
<div class="col-xs-10">
#*#Html.EditorFor(x => x.Holds.Last().When, new {})*#
</div>
</div>
}
The Holds collection can also be null so doing Last() in that case will case an null exception even if that did work.
This seems like something simple and I have this pattern in a couple places in my database. Can anyone recommend a good way to handle this situation?
Thanks!
You should use a view model for this because you wont get a very good response in your HttpPost action when you post this back
public class OrderViewModel
{
public OrderViewModel()
{
Order = new Order();
Hold = new Hold();
}
public Order Order { get; set; }
public Hold Hold { get; set; }
}
public ActionResult Edit(int id)
{
var o = from o context.Order.Include("Holds").Single(id);
var model = new OrderViewModel()
{
Order = o
}
if (o.Holds.Count() > 0)
model.Hold = o.Holds.Last();
return View(model);
}
then just use EditorFors
#model OrderViewModel
#using (Html.BeginForm("Update", "Order", FormMethod.Post, new {}))
{
<div class="form-group row">
#Html.LabelFor(x => x.Order.Name, new { #class = "col-xs-2" })
<div class="col-xs-10">
#Html.EditorFor(x => x.Order.Name, new { #class = "form-control"})
</div>
</div>
<div class="form-group row">
<label class="col-xs-2>When</label>
<div class="col-xs-10">
#Html.EditorFor(x => x.Hold.When)
</div>
</div>
}
First, instead of using Last() you should use LastOrDefault() and then do proper null-checking. Last() raises an exception is nothing is found, while LastOrDefault simply returns null in that case.
Second, using Last() or LastOrDefault() will not generate the proper input names via EditorFor, so once you post, the modelbinder won't know what to do with the value. Instead, you need to use indexing:
#if (Model.Holds.Any())
{
var lastIndex = Model.Holds.Count() - 1;
<div class="form-group row">
<label class="col-xs-2">When</label>
<div class="col-xs-10">
#Html.EditorFor(x => x.Holds[lastIndex].When, new {})
</div>
</div>
}

How do I bind a datatable to model and then to a dropdownlist in mvc?

I am very confused by how to accomplish this, I have seen these: reference to similar question 1 & reference to similar question 2 None of these two question answers explains how I bind the actual datatable variable to the model since they are specified to the dropdownlist part more.
I have tried using two methods: One was to bind a list from a model to the datatable string and the other was to create a model class with a string that I bind by creating a list of the string object in the model in the controller. But my problem remains in that the datatable variables and the model item it is passed to dies inside the foreach.
So how should I use the model correctly to bind the datatable to the dropdownlist?
Controller:
BFProj2.Models.OurColumns o = new Models.OurColumns();
o.DCResults = new List<string>();
List<OurColumns> s = new List<OurColumns>();
for(int y = 0; y <csvData.Columns.Count; y++)
{
string dc = csvData.Columns[y].ColumnName.ToString();
//When the list is created in the model.
o.DCResults.Add(dc.ToString());
//when the list is created in the controller.
foreach(OurColumns dc1 in s)
{
dc1.result = dc;
}
}
//Still in try...
//
//
// Here the former binding to the database began.
//
//
}
catch (Exception ex)
{
//return View("Error"+ ex.GetType().ToString());
}
//csvData is {Table1}
}
return View();
}
csvData is the datatable.
Model:
namespace BFProj2.Models
{
public class OurColumns
{
//[DisplayName("Password")]
public string Password { get; set; }
//[DisplayName("Email")]
public string Email { get; set; }
//[DisplayName("Comment")]
public string Comment { get; set; }
//[DisplayName("Username")]
public string UserName { get; set; }
//[DisplayName("Firstname")]
public string FirstName { get; set; }
//[DisplayName("Lastname")]
public string LastName { get; set; }
//[DisplayName("Last activity date")]
public DateTime? LastUpdateDate { get; set; }
//[DisplayName("Title")]
public string Title { get; set; }
//[DisplayName("Abstract number")]
public int AbstrNum { get; set; }
//[DisplayName("Poster title")]
public string PosterTitle { get; set; }
//[DisplayName("Workshop")]
public string Workshop { get; set; }
//[DisplayName("Keywords")]
public string Keywords { get; set; }
//[DisplayName("Institution")]
public string Institution { get; set; }
//[DisplayName("Collaboration email")]
public string CollabEmail { get; set; }
public string SessionDate { get; set; }
//[DisplayName("DCResults")]
public List<string> DCResults { get; set; }
public string result { get; set; }
public List<string> SelectedDCResults { get; set; }
}
//public class SelectedDCResults
//{
// public string result { get; set; }
//}
}
View:
#model BFProj2.Models.OurColumns
#{
ViewBag.Title = "Importcsv";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Import CSV</h2>
#Html.EditorFor(model => model.FirstName)
<div class="display-field">
#Html.DropDownListFor(m => m.result, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.LastName)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.Email)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.UserName)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.Comment)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.Title)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.Workshop)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.AbstrNum)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.PosterTitle)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.Keywords)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.Institution)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
#Html.EditorFor(model => model.CollabEmail)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
<!--Add session date to UserInput table as string format-->
#Html.EditorFor(model => model.SessionDate)
<div class="display-field">
#Html.DropDownListFor(m => m.SelectedDCResults, new SelectList(Model.DCResults))
</div>
First, get this code out of your controller. In MVC controllers should be thin – their responsibility should be figuring out which View to render and passing data to and from the Views and the business layer.
Second, your View is strongly typed to the OurColumns object an instance of the OurColumns object is never passed the view. It looks like you need a ViewModel that has a collection of DCResults for your DropDownList and a string to capture the selected value. It is not strictly necessary to have a separate “Selected” item, but I like how it simplifies code – it’s a ViewModel after all.
public class ViewModel {
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public List<string> DCResults { get; set; }
public string SelectedDCResult { get; set; }
}
Your controller should be responsible for creating the View Model on the GET request and parse the ViewModel into the Business Object (or past that along to a service in a more layered application).
public ActionResult Get()
{
var model = new ViewModel {
DCResults = this.DcResultRepos.DCResults
};
return View(model);
}
public ActionResult Post(ViewModel model) {
if (ModelState.IsValid) {
//do something
}
return View("Another View");
}
If you are not using an ORM for persistent storage to object binding, then you will need to create your own, in another class so you can abstract away that binding from the WebUI. For the previous example, I used the following signature:
private class DCResultRepository {
public List<string> DCResults { get; }
}
In the body of the get (or helper method) you could process your DataTable and use yield return to create an IEnumerable that would allow you to use Linq in your controller. Like this:
private DataTable table;
public IEnumerable<Model> DCResults {
get {
//do something to get datatable
foreach(var row in table.Rows){
yield return new Model(){
//initialize values
};
}
}
}

Error post using begincollectionitem MVC C#

I'm using begincollectionitem component, and when trying to save data is giving error at line db.SaveChanges();. I use MVC 4 e Razor.
This message error:
The operation failed: The relationship could not be changed because
one or more of the foreign-key properties is non-nullable. When a
change is made to a relationship, the related foreign-key property is
set to a null value. If the foreign-key does not support null values,
a new relationship must be defined, the foreign-key property must be
assigned another non-null value, or the unrelated object must be
deleted.
A minha implementação é esta:
Model
public class ProdutoPadrao : IEntidadeBase
{
[Key]
public int ProdutoPadraoID { get; set; }
[Display(Name = "Descrição")]
public string Descricao { get; set; }
[Display(Name = "Detalhe")]
public string Detalhe { get; set; }
public virtual ICollection<ProdutoPadraoCaracteristica> ListaProdutoCaracteristica { get; set; }
}
public class ProdutoPadraoCaracteristica : IEntidadeBase
{
[Key]
public int ProdutoPadraoCaracteristicaID { get; set; }
public int ProdutoPadraoID { get; set; }
public string Descricao { get; set; }
public int TipoCaracteristicaID { get; set; }
[ForeignKey("ProdutoPadraoID")]
public virtual ProdutoPadrao ProdutoPadrao { get; set; }
}
Controller GET
[ControleDeAcesso(TipoAcao.Normal)]
[Authorize]
public ActionResult Detalhar(int id)
{
using (var db = new ERPContext())
{
var produtoPadrao = db.ProdutoPadrao.Include("ListaProdutoCaracteristica").Where(w => w.ProdutoPadraoID == id).ToList().FirstOrDefault();
var retorno = EntidadeBaseExt.ValidarRegistro(produtoPadrao, TipoAcao.Visualizar);
if (retorno != "")
{
TempData["MsgRetornoError"] = retorno;
return RedirectToAction("Index", "Home");
}
ViewBag.ListaCaracteristica = new SelectList(ListagemPadrao.ListaTipoCaracteristica(), "Key", "Texto");
ViewBag.ListaUnidadeMedida = new SelectList(db.UnidadeMedida.ToListERP().Select(l => new ItemLPesquisa { Key = l.UnidadeMedidaID, Texto = l.Descricao }).ToArray(), "Key", "Texto");
return View(produtoPadrao);
}
}
Controller POST
[Authorize]
[HttpPost]
[ControleDeAcesso(TipoAcao.Normal)]
public ActionResult Detalhar(string btnSubmit, ProdutoPadrao model)
{
if (!ModelState.IsValid)
{
return View(model);
}
using (var db = new ERPContext())
{
var produtoPadrao = db.ProdutoPadrao.Include("ListaProdutoCaracteristica").Where(w => w.ProdutoPadraoID == model.ProdutoPadraoID).ToList().FirstOrDefault();
var retorno = FlexGestor.Helpers.EntidadeBaseExt.ValidarRegistro(produtoPadrao, TipoAcao.Gravar);
if (retorno != "")
{
TempData["MsgRetornoError"] = retorno;
return RedirectToAction("Index", "Home");
}
if (btnSubmit != "Excluir")
UpdateModel(produtoPadrao);
FlexGestor.Helpers.EntidadeBaseExt.AtribuirValores(produtoPadrao, btnSubmit);
db.Entry(produtoPadrao).State = EntityState.Modified;
db.SaveChanges();
if (btnSubmit == "Excluir")
return RedirectToAction("Index", controller);
return RedirectToAction("Detalhar", controller, new { id = model.ProdutoPadraoID });
}
}
View
#model FlexGestor.Models.ProdutoPadrao
#using (Html.BeginForm())
{
<div class="row">
#Html.TituloPagina("Visualizando Produto Padrão", "Clique para abrir a ajuda", "#help_produtoPadrao")
#Html.HiddenFor(m => m.ProdutoPadraoID)
<div class="col-md-12">
#Html.LabelFor(m => m.Descricao) #Html.ValidationMessageFor(m => m.Descricao)
#Html.TextBoxFor(m => m.Descricao, new { #class = "form-control" })
</div>
<div class="col-md-12">
#Html.LabelFor(m => m.Detalhe) #Html.ValidationMessageFor(m => m.Detalhe)
#Html.TextAreaFor(m => m.Detalhe, new { #class = "form-control", #rows = "4" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ListaProdutoCaracteristica)
<div class="controls">
<ul id="PhonesEditor" style="list-style-type: none">
#if (Model.ListaProdutoCaracteristica != null)
{
foreach (var item in Model.ListaProdutoCaracteristica)
{
Html.RenderPartial("_CustomerPhonesEditor", item);
}
}
</ul>
</div>
<p><a id="addAnother" class="small-button">AddPhone</a></p>
</div>
<div class="row">
<div class="col-md-12">
#Html.BotaoTelaDetalhar()
</div>
</div>
}
View Detail
#model FlexGestor.Models.ProdutoPadraoCaracteristica
#using (Html.BeginCollectionItem("ListaProdutoCaracteristica"))
{
#Html.HiddenFor(m => m.ProdutoPadraoID)
#Html.HiddenFor(m => m.ProdutoPadraoCaracteristicaID)
<div class="col-md-3">
#Html.LabelFor(m => m.TipoCaracteristicaID) #Html.ValidationMessageFor(m => m.TipoCaracteristicaID)
#Html.DropDownList("TipoCaracteristicaID", (SelectList)ViewBag.ListaCaracteristica, String.Empty,
new { #class = "form-control" })
</div>
<div class="col-md-9">
#Html.LabelFor(m => m.Descricao) #Html.ValidationMessageFor(m => m.Descricao)
#Html.TextBoxFor(m => m.Descricao, new { #class = "form-control" })
</div>
<div class="form-group">
<div class="controls">
<a onclick="$(this).parent().parent().parent().remove();" class="small-button" style="float: left;">Delete</a>
</div>
</div>
}
The below line is causing the problem
model.ListaProdutoCaracteristica = null;
It would cause the below property to be null, but it is not a nullable type
public int ProdutoPadraoID { get; set; }
If you want to be able to orphan records in this way, then you need to change it to a nullable int:
public int? ProdutoPadraoID { get; set; }

Categories

Resources