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.
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.
It is Great Answer. Thx a lot @topher !!!
– Marcin Rakoczy
Aug 23 at 10:20