Edit and delete a specific view model in a list - c#

I am making a shopping cart and for keeping track of the cart I have a session which contains a list of product view models.
This is the action method for adding to cart:
public ActionResult AddToCart(string id)
{
List<CartVM> cartVMList = new List<CartVM>();
CartVM cartVM = new CartVM();
int productId = Int32.Parse(id);
Db db = new Db();
var result = db.Products.FirstOrDefault(x => x.Id == productId);
decimal price = result.Price;
cartVM.ProductId = productId;
cartVM.Quantity = 1;
cartVM.Price = price;
if (Session["cart"] != null)
{
cartVMList = (List<CartVM>)Session["cart"];
cartVMList.Add(cartVM);
}
else
{
cartVMList.Add(cartVM);
}
Session["cart"] = cartVMList;
//return Content(id);
return RedirectToAction("Index", "ShoppingCart");
}
It works when adding new products, so e.g. if I add 5 new products the session will contain a list of 5 products, but how do I edit and delete a specific view model from the list, based on for example the ProductId ?

I haven't tested it, but the following should work. All you need to do is grab the cart list like you did when adding to cart. Instead of adding a new item, you just edit the object in the list or remove it from the list.
Technically, unless Session does something special, you shouldn't need to re-save the list to the Session if you got it from the session, since a list is a reference type.
public ActionResult EditCartItem(string id, int quantity, decimal price)
{
if (Session["cart"] != null)
{
var cartVMList = (List<CartVM>) Session["cart"];
var itemToEdit = cartVMList.FirstOrDefault(cartVM => cartVM.Id == id);
if(itemToEdit == null)
return this.HttpNotFound();
itemToEdit.Quantity = quantity;
itemToEdit.Price = price;
}
}
public ActionResult RemoveFromCart(string id)
{
if (Session["cart"] != null)
{
var cartVMList = (List<CartVM>) Session["cart"];
var itemToRemove = cartVMList.FirstOrDefault(cartVM => cartVM.Id == id);
if(itemToRemove == null)
return this.HttpNotFound();
cartVMList.Remove(itemToRemove);
}
}

Related

Auto increment column for specific Id in some table related to anther table C# mvc

I have a table named Payment which has a column named IndexOrder and all I need when I add a new payment, the AddEdit function will check first if there is any value in IndexOrder Column for this specific Id then increment Indexorder with 1 and so on for every new PaymentId. my AddEdit function code is like:
[HttpPost]
public ActionResult AddEdit(PaymentModel model )
{
if (ModelState.IsValid)
{
var userId = User.Identity.GetUserId();
Payment obj = context.Payment
.Where(p => p.Id == model.Id).FirstOrDefault();
if (obj == null)
{
obj = new Payment();
if (model.File != null)
{
Guid nme = Guid.NewGuid();
string filename = nme + Path.GetExtension(model.File.FileName);
string filepath = Path.Combine(Server.MapPath("/FilesUpload/") + filename);
model.File.SaveAs(filepath);
obj.Path = filename;
}
Mapper.FillObjectFromModel(obj, model);
obj.CreatedBy = userId;
obj.ModifiedBy = userId;
obj.CreatedAt = DateTime.Now;
obj.ModifiedAt = DateTime.Now;
context.Payment.Add(obj);
context.SaveChanges();
So did i get that right? For every new payment that relates to a specific id (assuming a product or something) you want aincremented IndexOrder?
I would not use an IndexOrder column for that but instead just order by timestamp. Assuming you need that for kind of transactionhistory just read them payments like
context.Payments.Where(x => x.ProductId == myProductId).OrderBy(x => x.timestamp);
But to answer your question this should be quite simple, e.g:
var nextIndex = context.Payments.Where(x => x.ProductId == myProductId).Count +1;

C# - Retrieve data from persistence storage and save it to the view model

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?
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?

Trying to Add to Database: Collection was modified; enumeration operation may not execute?

Below is my controller That I am calling from a href button and passing an id. The href button is a duplicate button which is meant to create a copy of the selected module and add it to the database and then return it.
public ActionResult dupe(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
MODULE Modules = db.MODULE.Find(id);
if (Modules == null)
{
return HttpNotFound();
}
else
{
MODULE newMOd = new MODULE();
newMOd.APPLY__FINISH = Modules.APPLY__FINISH;
newMOd.CREATED_BY = Modules.CREATED_BY;
newMOd.CREATED_DATE = Modules.CREATED_DATE;
newMOd.MODULE_DESC = "Duplicate-"+Modules.MODULE_DESC;
newMOd.MODULE_TYPE = Modules.MODULE_TYPE;
newMOd.MODULE_TYPE1 = Modules.MODULE_TYPE1;
newMOd.PRODUCT_LINE = Modules.PRODUCT_LINE;
newMOd.MODULE_NAME = "Duplicate-" + Modules.MODULE_NAME;
foreach (MODULE_PARTS mp in Modules.MODULE_PARTS)
{
newMOd.MODULE_PARTS.Add(mp);
}
foreach (MODULE_OPTION mo in Modules.MODULE_OPTION)
{
MODULE_OPTION m = new MODULE_OPTION();
m.OPTION_NAME = mo.OPTION_NAME;
m.OPTION_TYPE = mo.OPTION_TYPE;
m.PRODUCT_LINE = mo.PRODUCT_LINE;
m.ADDED_BY = mo.ADDED_BY;
m.ADDED_ON = mo.ADDED_ON;
m.DEFAULT_FACTOR = mo.DEFAULT_FACTOR;
foreach (OPTION_PARTS op in mo.OPTION_PARTS)
{
m.OPTION_PARTS.Add(op);
}
newMOd.MODULE_OPTION.Add(mo);
}
newMOd.MODULE_PARTS = Modules.MODULE_PARTS;
newMOd.MODULE_OPTION = Modules.MODULE_OPTION;
db.MODULE.Add(newMOd);
db.SaveChanges();
}
return View(Modules);
}
This is my controller method, and when I try to add this module to database I get collection modified error. I'm not sure how or where?
enter image description here
The exception message in this case is quite clear... you cannot modify a member of a collection you are currently iterating over. It's that simple.

Edit table data using auto mapper

Hi i am building a web application for school.
I am trying to update student information, i already did teacher part
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(Teacher teacher)
{
if (!ModelState.IsValid)
{
var data = teacher;
return View("TeacherForm", data);
}
if (teacher.Id == 0)
_context.Teachers.Add(teacher);
else
{
var dataInDb = _context.Teachers.Single(c => c.Id == teacher.Id);
dataInDb.Name = teacher.Name;
dataInDb.Designation = teacher.Designation;
dataInDb.EducationalQualification = teacher.EducationalQualification;
dataInDb.DateOfBirth = teacher.DateOfBirth;
dataInDb.PhoneNumber = teacher.PhoneNumber;
dataInDb.StartDate = teacher.StartDate;
dataInDb.EndDate = teacher.EndDate;
dataInDb.Status = teacher.Status;
}
_context.SaveChanges();
return RedirectToAction("Index", "Teacher");
}
But in Student part i want to use auto mapper for map data
if (student.Id == 0)
_context.Students.Add(student);
else
{
var dataInDb = _context.Students.Single(c => c.Id == student.Id);
Mapper.Map(student, dataInDb);
}
but its not working. I try to edit data but the table data remain same.
its relay difficult to write every property for student.
how can i solve this problem?

Enter new data in db (EF)

I have method in controller
It receive data from post request and write to table
Here is code
[ResponseType(typeof(TimeTable))]
public IHttpActionResult PostTimeTable(TimeTable timeTable)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (ModelState.IsValid)
{
DateTime dt = DateTime.Today;
TimeTable c = (from x in db.TimeTables
where x.Company == timeTable.Company && x.INN == timeTable.INN
select x).First();
c.StartPause = timeTable.StartPause;
c.StartDay = timeTable.StartDay;
c.EndPause = timeTable.EndPause;
c.EndDay = timeTable.EndDay;
db.SaveChanges();
}
db.TimeTables.Add(timeTable);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = timeTable.Id }, timeTable);
}
But it works well when record with INN and Company already in db.
But if it not in database I need to create new entry.
How I need to modify this method?
You can use a flag (exisingCompanyFlag) for edit mode or add new mode like this
bool existingCompanyFlag = true;
TimeTable c = (from x in db.TimeTables
where x.Company == timeTable.Company && x.INN == timeTable.INN
select x).FirstOrDefult();
if (c == null)
{
existingCompanyFlag = false;
c = new TimeTable();
}
c.StartPause = timeTable.StartPause;
c.StartDay = timeTable.StartDay;
c.EndPause = timeTable.EndPause;
c.EndDay = timeTable.EndDay;
if (!existingCompanyFlag)
db.TimeTables.Add(c);
You need a separate branch in your code for the insert case.
if (ModelState.IsValid) {
if (addingNewRow) {
TimeTable tt = new TimeTable {
// Populate properties (except identity columns)
};
db.TimeTables.Add(tt);
} else {
// update
}
db.SaveChanges();
}
To link to other entities use one of:
Assign instances:
x.Company = theCompany;
or, assign the instance id
x.CompanyId = companyId;
(#1 is easier if you already have the other entity loaded or are creating it – EF will sort out the ids – while #2 saves loading the whole other entity.)

Categories