简体   繁体   中英

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 :

  • a) create new Customer and Address or
  • b) For existing Customer add new Address

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 :

  • a) create new Customer and Address or
  • b) For existing Customer add new Address

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

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.

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"/>

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

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM