asp.net mvc - Better Way To Edit A View Model in MVC -
i came working example of how display (get) , edit (post) view model consisting of 3 models in mvc. however, mvc skills limited , looking suggestions on "the right way" should doing this. part in question i'm sending form fields individually rather view model, couldn't figure out how do.
here models
name
public partial class name { public name() { this.addresses = new hashset<address>(); this.emails = new hashset<email>(); } public int id { get; set; } public string first_name { get; set; } public string last_name { get; set; } public virtual icollection<address> addresses { get; set; } public virtual icollection<email> emails { get; set; } } address
public partial class address { public int address_id { get; set; } public int nameid { get; set; } public string address_1 { get; set; } public string city { get; set; } public string state { get; set; } public string zip { get; set; } public virtual name name { get; set; } } public partial class email { public int email_id { get; set; } public int nameid { get; set; } public string email { get; set; } public virtual name name { get; set; } } my view model made of fields 3 models.
public class contactformviewmodel { public int? id { get; set; } public string first_name { get; set; } public string last_name { get; set; } public string address_1 { get; set; } public string city { get; set; } public string state { get; set; } public string zip { get; set; } public string email { get; set; } } the method of edit page (in controller)
// get: names/edit/5 //the method takes id url , passes query return data specific record public actionresult edit(int id) { //this query outer join of name, address , email models/tables var query = n in db.names join in db.addresses on n.id equals a.nameid na in na.defaultifempty() join e in db.emails on n.id equals e.nameid ne e in ne.defaultifempty() n.id == id //creates new instance of view model, populated query data select new contactformviewmodel { id = id, first_name = n.first_name, last_name = n.last_name, address_1 = a.address_1, city = a.city, state = a.state, zip = a.zip, email = e.email }; //returns query view return view(query); } the post method of edit page (in controller)
// post: names/edit/5 [httppost] [validateantiforgerytoken] //the post method takes individual form field data , passes queries update 3 models separately public actionresult edit(int id, string first_name, string last_name, string address_1, string city, string state, string zip, string email) { if (modelstate.isvalid) { //query database row updated. var queryn = n in db.names n.id == id select n; var querya = in db.addresses a.nameid == id select a; var querye = e in db.emails e.nameid == id select e; //assign form field data fields in model foreach (name n in queryn) { n.first_name = first_name; n.last_name = last_name; } //if there no address records, insert if (!querya.any()) { //new instance of address var address = new address { nameid = id, address_1 = address_1, city = city, state = state, zip = zip }; db.addresses.add(address); } //else, if there address records, update else { foreach (address in querya) { a.address_1 = address_1; a.city = city; a.state = state; a.zip = zip; } } //if there no email records, insert if (!querye.any()) { //new instance of email var email = new email { nameid = id, email = email }; db.emails.add(email); } //else, if there email records, update else { foreach (email e in querye) { e.email = email; } } //// submit changes database. try { db.savechanges(); } catch (exception ex) { console.writeline(ex); // provide exceptions. } } return redirecttoaction("index"); } the view
@model iqueryable<mdtestapplication.viewmodel.contactformviewmodel> @{ viewbag.title = "edit"; } <h2>edit</h2> @using (html.beginform()) { @html.antiforgerytoken() <div class="form-horizontal"> <h4>name</h4> <hr /> @*uses foreach loop field data view model*@ @foreach (var item in model) { @html.validationsummary(true, "", new { @class = "text-danger" }) @html.hiddenfor(modelitem => item.id) <div class="form-group"> @html.labelfor(modelitem => item.first_name, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @*using razor syntax output value*@ @*using form field 'name' attribute posting controller*@ <input type="text" name="first_name" value="@item.first_name" class="form-control" /> </div> </div> <div class="form-group"> @html.labelfor(modelitem => item.last_name, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <input type="text" name="last_name" value="@item.last_name" class="form-control" /> </div> </div> <div class="form-group"> @html.labelfor(modelitem => item.address_1, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <input type="text" name="address_1" value="@item.address_1" class="form-control" /> </div> </div> <div class="form-group"> @html.labelfor(modelitem => item.city, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <input type="text" name="city" value="@item.city" class="form-control" /> </div> </div> <div class="form-group"> @html.labelfor(modelitem => item.state, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <input type="text" name="state" value="@item.state" class="form-control" /> </div> </div> <div class="form-group"> @html.labelfor(modelitem => item.zip, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <input type="text" name="zip" value="@item.zip" class="form-control" /> </div> </div> <div class="form-group"> @html.labelfor(modelitem => item.email, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <input type="text" name="email" value="@item.email" class="form-control" /> </div> </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> } <div> @html.actionlink("back list", "index") </div> update
here's additional insert , update code added alex's answer below. use same setup address , email.
foreach (var address in model.addresses) { var addresstoupdate = name.addresses.firstordefault(a => addressid== address.addressid); if (addresstoupdate != default(address)) { // preform update addresstoupdate.addressid = address.addressid; addresstoupdate.city = address.city; addresstoupdate.state = address.state; addresstoupdate.zip = address.zip; } else { //perform insert var newaddress = new address { nameid = model.id, address1 = address.address1, city = address.city, state = address.state, zip = address.zip }; db.addresses.add(newaddress); } }
first of let me start naming convention.
this:
public int address_id { get; set; } public int nameid { get; set; } is bad have no naming convention @ all, properties pascalcase, others capital case underscores. advise install tool enforce apply set of style , consistency rules(for example stylecop). in general common use pascalcase properties.
once apply models like:
public partial class address { public int addressid { get; set; } public int nameid { get; set; } public string address1 { get; set; } public string city { get; set; } public string state { get; set; } public string zip { get; set; } public virtual name name { get; set; } } second thing: if understand correct trying edit data 1 user: his(or hers) first , last name, list of addresses , lit of emails. if right both view , viewmodel wrong. viewmodel following:
public class contactformviewmodel { public int nameid { get; set; } public string firstname { get; set; } public string lastname { get; set; } public ilist<address> addresses { get; set; } public ilist<emails> { get; set; } } controller(updated):
// get: names/edit/5 //the method takes id url , passes query //return data specific record public actionresult edit(int id) { //you don't need joins since have navigation properies! var name = db.names.firstordefault(n => n.id == id); contactformviewmodel model; if(name == default(name)) { model = new contactformviewmodel{ addresses = new list<address>(), emails = new list<email>() }; } else { model = new contactformviewmodel { nameid = name.nameid , firstname = name.firstname, lastname = name.lastname , addresses = name.addresses.tolist(), emails = name.emails.tolist(), }; } if(!model.addresses.any()) { model.addresses.add(new address()); } if(!model.emails.any()) { model.emails.add(new email()); } //returns query view return view(model); } view:
@model mdtestapplication.viewmodel.contactformviewmodel @{ viewbag.title = "edit"; } <h2>edit</h2> @using (html.beginform()) { @html.antiforgerytoken() <div class="form-horizontal"> <h4>name</h4> <hr /> @html.validationsummary(true, "", new { @class = "text-danger" }) @html.hiddenfor(model => model.nameid) <div class="form-group"> @html.labelfor(model => model.firstname, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @html.editorfor(model => model.firstname, new { @class = "firstname" }) </div> </div> <div class="form-group"> @html.labelfor(model => model.lastname, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @html.editorfor(model => item.lastname, new { @class = "firstname" }) </div> </div> @for (int = 0; < model.addresses.count; i++) { @html.hiddenfor(model => model.addresses[i].addressid) <div class="form-group"> @html.labelfor(model => model.addresses[i].address1, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @html.editorfor(model => model.addresses[i].address1, new { @class = "firstname" }) </div> </div> <div class="form-group"> @html.labelfor(model => model.addresses[i].city, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @html.editorfor(model => model.addresses[i].city, new { @class = "firstname" }) </div> </div> /// continue here address properties } @for (int = 0; < model.emails.count; i++) { @html.hiddenfor(model => model.emails[i].emailid) <div class="form-group"> @html.labelfor(model => model.emails[i].email, htmlattributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @html.editorfor(model => model.emails[i].email, new { @class = "firstname" }) </div> </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> } <div> @html.actionlink("back list", "index") </div> edit action in controller:
public actionresult edit(contactformviewmodel model) { if (modelstate.isvalid) { //query database row updated. var name = db.names.firstordefault( n => n.nameid == model.nameid); if(name != default(name)) { name.firstname = model.firstname; name.lastname = model.lastname; bool hasaddresses = name.addresses.any(); foreach(var address in model.addresses) { var addresstoupdate = name.addresses.firstordefault(a => a.addressid == address.addressid); if(addresstoupdate != default(address)) { // preform update } else { //perform insert } } foreach(var email in model.emails) { var emailtoupdate = name.emails.firstordefault(a => a.emailid == email.emailid); if(emailtoupdate != default(email)) { // preform update } else { //perform insert } } db.savechanges(); } } }
Comments
Post a Comment