how to save data from two models (relation one to many) from one viewModel in MVC c#?

how to save data from two models (relation one to many) from one viewModel in MVC c#?



I need to have only one view and :



But I dont known what is wrong with my Save action.
How to set Customer's AddressId to new Address Id ( jus created) ?



I use:


public class ApplicationDbContext : IdentityDbContext<ApplicationUser>

public DbSet<Customer> Customers get; set;
public DbSet<Address> Addresses get; set;



I have two models:


public class Customer

public int Id get; set;

[Required]
[StringLength(255)]
public string Name get; set;

public Address Address get; set;
public int? AddressId get; set;


public class Address

public int Id get; set;

[Required]
[StringLength(255)]
public string Town get; set;



And one viewModel


public class CustomerAddressViewModels

public Customer Customer get; set;
public Address Addresses get; set;



Then I create a controller with good working Details action


public class CustomerDetailsController : Controller

private ApplicationDbContext db = new ApplicationDbContext();

// GET: CustomerDetails/Details/5
public async Task<ActionResult> Details(int id)

if (id == null)

return new HttpStatusCodeResult(HttpStatusCode.BadRequest);


Customer customer = await db.Customers
.Include(c => c.Address)
.SingleOrDefaultAsync(c => c.Id == id);

return View("CustomerAddressView");




I wrote Save action for Create and Update cases:


[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Save(Customer customer, Address address)


if (!ModelState.IsValid)

var vieModel = new CustomerAddressViewModels();

return View("CustomerAddressView", vieModel);


if (customer.AddressId == 0)

address.StreetName = customer.Address.StreetName;
db.Addresses.Add(address);

else

var addressInDb = db.Addresses
.Single(a => a.Id == customer.AddressId);

addressInDb.StreetName = customer.Address.StreetName;


if (customer.Id == 0)

db.Customers.Add(customer);

else

var customerInDb = db.Customers
.Single(c => c.Id == customer.Id);

customerInDb.Name = customer.Name;
customerInDb.AddressId = customer.AddressId;


await db.SaveChangesAsync();

return RedirectToAction("Index","Customers");



I need to have only one view and :



But I dont known what is wrong with my Save action.
How to set Customer's AddressId to new Address Id ( jus created) ?




1 Answer
1



When inserting an address you should add the address to the customer.Addresses collection rather than to db.Address directly, then EF should handle populating the keys for you.


customer.Addresses


db.Address



There are some other things worth mentioning here I think.



You should use a viewmodel class that represents the objects being passed to and from your views instead of using your entities directly. So I'd recommend a class like this:


public class CustomerViewModel


public int CustomerOd get; set;
//<... other properties for customer>
public AddressViewModel Address get; set;


public class AddressViewModel

//Address propties



This allows you to have view specific properties on your object that can help with various things (like whether to hide or show a section for example) based on a value that isn't inside your Customers entity.



Then your controller Action save looks like this:


[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Save(CustomerViewModel model)

//preceeding code
var customer = db.Customers.SingleOrDefault(x => x.CustomerId == model.CustomerId)

if (customer.Address == null)

var address = new Address()

StreetName = model.Address.StreetName
;
Customer.Addresses.Add(address);




You then map or populate the data to your Entity from the ViewModel object. It involves a little extra work but allows for more flexibility.



What's happening in your Details action? You get customers but then don't pass it to your view?


Customer customer = await db.Customers
.Include(c => c.Address)
.SingleOrDefaultAsync(c => c.Id == id);

return View("CustomerAddressView");



In order for the framework to correctly bind your object from the form to your view for the address object, you should describe your html objects in the same structure of your object. So you could have an input like this



<input value="@Model.Address.StreetName" name="Address.StreetName"/>


<input value="@Model.Address.StreetName" name="Address.StreetName"/>



and it should bind that value to the address object when you post back.



Hope this helps.





It is Great Answer. Thx a lot @topher !!!
– Marcin Rakoczy
Aug 23 at 10:20






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)