MVC Multiple tables one model

13,846

Solution 1

In your CustomerGarment class, you should have:

public class CustomerGarment
{
    public int CustomerGarmentId { get; set; }
    public int CustomerId { get; set; }
    public int OrderId { get; set; }
    public int GarmentJacketId { get; set; }
    public int GarmentShirtId { get; set; }

    public virtual Customer Customer { get; set; }
    public virtual Order Order { get; set; }
    public virtual GarmentJacket GarmentJacket { get; set; }
    public virtual GarmentShirt GarmentShirt { get; set; }
}

And, then, in your View, your DropDownList will look like:

@Html.DropDownListFor(m => m.GarmentJacketId, (SelectList)ViewBag.GarmentJacket, new {style="width:312px;height:30px;margin-top:2px;margin-bottom:5px"})

Your DropDownList only posts one value, which is the GarmentJacketId. You can't bind that Id to the whole GarmentJacket class.

By the way, you also need to replace your hidden inputs with these:

@Html.HiddenFor(model => model.OrderId)
@Html.HiddenFor(model => model.CustomerId)

Solution 2

I think I know your problem. As you suggested in you comment above you need to post everything you want retained in the view. This is one of the differences beteween webforms and MVC, webforms has viewstate that could contain information that you don't explicitly add to the view and post back, giving the impression of state. In MVC you have to add it to the view.

On the other hand you don't need to pass in more information than you need either. You pass inn the customerId as a hidden field. On post method you get the customer from the db using the Id, then you add the order to the customer.

I have some questions about your design, but given that a customer holds a collection of Orders, you could do something like this:

 [HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddGarments(CustomerGarment cg)
{

    // Get the customer from the database
    var customer = db.Customers.Find(c=>c.id==cb.Customer.Id)
    var order = new Order();
    //Create your order here using information from CustomerGarment model
    //If the model already holds a valid Order object then just add it.
    //i.e. you could get a Garment object from the DB using the GarmentId from
    //the ViewModel if you really need more than just the Id to create the order

    customer.Orders.Add(order);
    db.SaveChanges();
    return RedirectToAction("Index");

}
Share:
13,846
MichaelMcCabe
Author by

MichaelMcCabe

Studied Computer Science at Cardiff University. Have worked for many years as a Java and .NET developer for companies such as Red Hat, BAE Systems, and now leading a team of developers in south wales UK. Recently starting to learn MVC and more client side technologies to improve the software I write

Updated on June 04, 2022

Comments

  • MichaelMcCabe
    MichaelMcCabe over 1 year

    I am having difficulty with my understanding of MVC coming from an aspx world.

    I have a Model called CustomerGarment. This has a Order and a Customer along with a few garments.

    public class CustomerGarment
    {
        public int CustomerGarmentId { get; set; }
    
        public virtual Customer Customer { get; set; }
    
        public virtual Order Order { get; set; }
    
        public virtual GarmentJacket GarmentJacket { get; set; }
        public virtual GarmentShirt GarmentShirt { get; set; }
    }
    

    I have a method for get and post. When the page loads, it creates a new CustomerGarment instance and querys the database to fill the Customer and Order variables. I then use the viewbag to show on the screen a list of GarmentJackets and GarmentShirts

    The page then views and using the view I can access the model perfectly. Drop downs load with the viewbag contents and I can access all Customer and Order variables using the model I have passed.

    The problem I then face is when I use the HttpPost. The model is not passed back with the information I passed to it.

        public ActionResult AddGarments(int orderId, int customerId)
        {
            CustomerGarment cg = new CustomerGarment();
            cg.Order = (from a in db.Orders where a.OrderId == orderId select a).FirstOrDefault();
            cg.Customer = (from a in db.Customers where a.CustomerId == customerId select a).FirstOrDefault();
    
            var jackets = from a in db.GarmentJackets orderby a.Type, a.SleeveLengthInches, a.ChestSizeInches select a;
            var shirts= from a in db.GarmentKilts orderby a.PrimarySize, a.DropLength select a;
            ViewBag.GarmentJacket = new SelectList(jackets, "GarmentJacketId", "GarmentJacketId");
            ViewBag.GarmentShirt = new SelectList(shirts, "GarmentShirtId", "GarmentShirtId");
    
            return View(cg);
        }
    
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult AddGarments(CustomerGarment cg)
        {
            // Here, I do not have the customer info for example
            db.CustomerGarments.Add(cg);
            db.SaveChanges();
            return RedirectToAction("Index");
    
            return View(cg);
        }
    

    This is a bit of my view

    @Html.HiddenFor(model => model.Order.OrderId)
        @Html.HiddenFor(model => model.Order.CustomerId)
    
        <div class="display-field">
            @Html.DisplayFor(model => model.Customer.Name)
        </div>
    
    
        <div class="editor-label">
            @Html.LabelFor(model => model.GarmentJacket, "Jacket")
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(m => m.GarmentJacket, (SelectList)ViewBag.GarmentJacket, new {style="width:312px;height:30px;margin-top:2px;margin-bottom:5px"})
        </div>
    

    EDIT

    My Garment Jacket Model

    public class GarmentJacket : Garment
    {
        public int GarmentJacketId { get; set; }
    
        [Required]
        public string Type { get; set; }
    
        [Required]
        [Display(Name = "Chest Size")]
        public int ChestSizeInches { get; set; }
    
        [Required]
        [Display(Name = "Sleeve Length")]
        public int SleeveLengthInches { get; set; }
     }
    
    public class Garment
    {
        [DataType(DataType.Date)]
        public DateTime? DateRetired { get; set; }
    
        [Required]
        public string Barcode { get; set; }
    
        [Required]
        public bool Adults { get; set; }
    }