MVC Multiple tables one model
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");
}
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, 2022Comments
-
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 aOrder
and aCustomer
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 ofGarmentJacket
s andGarmentShirt
sThe 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; } }