问题
Hello I have a controller method that I want to return the view model of that looks like this
This is what it would look like if it was hard-coded
public ActionResult SpecialOrderSummary(int? id)
{
// Retrieve data from persistence storage and save it to the view model.
// But here I am just faking it.
var vm = new ItemViewModel
{
ItemId = 123,
ItemName = "Fake Item",
Parts = new List<ItemPartViewModel>
{
new ItemPartViewModel
{
PartId = 1,
PartName = "Part 1"
},
new ItemPartViewModel
{
PartId = 2,
PartName = "Part 2"
}
}
};
return View(vm);
}
But I obviously don't want it hard coded. So this is what I was trying to do instead to achieve my goal
public ActionResult SpecialOrderSummary(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
JobOrder jobOrder = db.JobOrders.Find(id);
if (jobOrder == null)
{
return HttpNotFound();
}
ViewBag.JobOrderID = jobOrder.ID;
ItemInstance ii = db.ItemInstances.Where(x => x.serialNumber == jobOrder.serialNumber).FirstOrDefault();
Item item = db.Items.Find(ii.ItemID);
var vm = new ItemViewModel
{
ItemId = item.ItemID,
ItemName = item.Name,
Parts = new List<ItemPartViewModel>
{
foreach(ItemHasParts ihp in item.IHP)
{
Part part = db.Parts.Find(ihp.PartID);
new ItemPartViewModel
{
PartId = part.ID,
PartName = part.Name
};
}
}
};
return View(vm);
}
But that doesn't work. As it doesn't seem to recognize the closing }
of the opening "Parts" and the opening "vm" bracket as it skips both. Why is this?
回答1:
Hmmm I thought I answered this question before: https://stackoverflow.com/a/62782124/2410655. Basically you can't have a for loop like that in the middle of the view model.
I would like to add 2 more things to it.
1. Id?
If the special order summary expects an ID, don't declare it as optional. If you do so, you have to add more logic to check whether there is an ID or not.
If the order summary expects an ID, just declare it as int id
. And if the client doesn't provide it, let the MVC framework handle the error. Now depending on your setup, your MVC might throw a 404, or 500, or a user-friendly page. It's up to you, the developer, to set it up.
2. Be careful on NullReference Exception
In your code example, I see you used FirstOrDefault()
on the item instance. That will bite you if it comes back as NULL and you call db.Items.Find(ii.ItemID)
...
So based on your example, I would change the code to:
public ActionResult SpecialOrderSummary(int id)
{
JObOrder jobOrder = db.JobOrders.Find(id);
if (jobOrder == null)
{
return HttpNotFound();
}
ItemInstance itemInstance = db.ItemInstances
.Where(x => x.serialNumber == jobOrder.serialNumber)
.FirstOrDefault();
Item item = null;
if (itemInstance != null)
{
item = db.Items.Find(itemInstance.ItemID);
}
var vm = new JobOrderSummaryViewModel
{
JobOrderId = jobOrder.ID,
Parts = new List<ItemPartViewModel>();
};
if (item != null)
{
vm.ItemId = item.ItemId;
vm.ItemName = item.ItemName;
foreach(ItemHasParts ihp in item.IHP)
{
// Does Part and Item have many-to-many relationships?
// If so, you might be able to get the part by
// ihp.Part instead of looking it up using the ID.
// Again, it depends on your setup.
Part part = db.Parts.Find(ihp.PartID);
if (part != null)
{
vm.Parts.Add(new ItemPartViewModel
{
PartId = part.ID,
PartName = part.Name
});
}
}
}
return View(vm);
}
Note:
You have additional calls back to the database inside the loop (db.Parts.Find(ihp.PartID);
). That will cause performance issue if you have huge data. Is there any way you can fetch all your data you needed once at the beginning?
来源:https://stackoverflow.com/questions/62780275/c-sharp-retrieve-data-from-persistence-storage-and-save-it-to-the-view-model