CheckOut Cart MVC - c#

I am trying to create a checkout for the cart in my webshop project for classe.
I want that every time that your press checkout it will take from the model Clothes.Amount 1 for each product that you have in the cart session.
and then I want to clean the cart.
In cart controller I have this three functions and one other to order but it is not important for this question i think.
The error is int this lines
Item.Cl.Amount--;
Delete(Item.Cl.Id);
Here is the code
private int isExisting(int id)
{
List<Item> cart = (List<Item>)Session["cart"];
for (int i = 0; i < cart.Count; i++)
{
if (cart[i].Cl.Id == id)
return i;
}return -1;
}
public ActionResult Delete(int idDelete)
{
int index = isExisting(idDelete);
List<Item> cart = (List<Item>)Session["cart"];
cart.RemoveAt(index);
Session["cart"] = cart;
return View("Order");
}
public ActionResult CheckOut(int idCheck)
{
int index = isExisting(idCheck);
if(index != -1) {
foreach (Item item in (List<Item>)Session["cart"]) {
Item.Cl.Amount--;
Delete(Item.Cl.Id);
}
}
return View();
}

From your question I am unable to see which error you are getting. But just looking at your code I would think that this is the classic "Collection was modified; enumeration operation may not execute".
In method CheckOut You are iterating over the item list in your session. While you're doing so you call the Delete method which removes an item from the list. That is simply not allowed...
If that is your issue you could change your second method to the following:
public ActionResult CheckOut(int idCheck)
{
int index = isExisting(idCheck);
if(index != -1) {
foreach (Item item in ((List<Item>)Session["cart"]).ToList()) {
Item.Cl.Amount--;
Delete(Item.Cl.Id);
}
}
return View();
}

Related

ShoppingCart ;Collection was modified; enumeration operation may not execute

I have a shopping cart list that I want to loop through, when the item is already in the cart the amount has to be increased, otherwise a new object has to be created.
I know you can't change a list during a loop,
so I tried to work with Tolist() but when I try that he only makes the first object and overwrites when I make the second one.
I don't get this fixed, can somebody help me fix it?
[HttpPost, ActionName("Details")]
[ValidateAntiForgeryToken]
public IActionResult DetailsPost(int id, DetailsProductViewModel detailsProductViewModel)
{
List<ShoppingCart> shoppingCartsList = new List<ShoppingCart>();
if (HttpContext.Session.Get<IEnumerable<ShoppingCart>>(WC.SessionCart)!=null
&& HttpContext.Session.Get<IEnumerable<ShoppingCart>>(WC.SessionCart).Count() > 0)
{
shoppingCartsList = HttpContext.Session.Get<List<ShoppingCart>>(WC.SessionCart);
foreach (var item in shoppingCartsList)
{
if (item.ProductId == id)
{
item.Aantal += 1;
}
else
{
shoppingCartsList.Add(new ShoppingCart { ProductId = id, Aantal = detailsProductViewModel.Product.Aantal });
}
}
}
else
{
shoppingCartsList.Add(new ShoppingCart { ProductId = id, Aantal = detailsProductViewModel.Product.Aantal });
}
HttpContext.Session.Set(WC.SessionCart, shoppingCartsList);
return RedirectToAction(nameof(Index));
}
you don't need a loop. just try to find the item in the list. if found, increase amount, if not create new one.
...//also check your shoppingCartsList is null or not
var product = shoppingCartsList.FirstOrDefault(x=>x.ProductId == id);
if(product == null)
{
shoppingCartsList.Add(new ShoppingCart { ProductId = id, Aantal = detailsProductViewModel.Product.Aantal });
}
else
{
product.Aantal++;
}
HttpContext.Session.Set(WC.SessionCart, shoppingCartsList);

Inventory UI acting strange in updating amounts

So I have an item class, an inventory class and the UIController scripts. When the player goes over the item on the field the player should have the item added to the inventory, if he/she has the item it should increase the amount by one.
The issue I'm having is the numbers on the UI are random and sometimes items add amounts other times they just use a new slot. I have added the three scripts I mentioned above.
public Item()
{
amount = 0;
}
public int GetItemAmount()
{
return amount;
}
public void IncreaseAmount(int amt)
{
amount += amt;
}
public void SpawnItem()
{
Instantiate(prefab);
}
public Inventory()
{
inventory = new List<Item>();
}
// Add item to inventory. if item is already in inventory, increase amount.
public void AddItem(Item item)
{
if (inventory.Count == 0)
{
inventory.Add(item);
}
else
{
for (int i = 0; i < GetInventory().Count; i++)
{
if (this.inventory[i] == item)
{
inventory[i].IncreaseAmount(1);
break;
}
else
{
inventory.Add(item);
}
break;
}
}
}
void Start()
{
player = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
inventoryItems = CreateInventoryItemUI(itemSlotImage);
}
private void Update()
{
var playerItems = player.inventory.GetInventory();
for (int i = 0; i <= playerItems.Count ; i++)
{
//Debug.Log("The value of i is : " + i);
if (playerItems[i] != null)
{
inventoryItems[i].GetComponentInChildren<Image>().sprite = playerItems[i].imageIcon;
var amountUI = inventoryItems[i].transform.Find("ItemSlotAmount").GetComponent<Text>();
amountUI.gameObject.SetActive(true);
amountUI.text = playerItems[i].GetItemAmount().ToString();
Debug.Log("The items being added will be: " + amountUI.text);
inventoryItems[i].gameObject.SetActive(true);
}
}
}
I think I just another set of eyes. I debugged and checked reference of the increase amount method and it's only used in the inventory script.
Any ideas would be very helpful.
You are checking if the added Item is exactly the same object as one in the list, as in the same reference. I'm assuming this is probably not what you want, please post the part of the code calling AddItem otherwise.
Two suggestions:
First, add an Id property to Item and compare if the item being added has the same Id, instead of comparing the references.
Second, this would probably be cleaner and more efficient if you used a Dictionary instead of a List for storing the items. Give it a try!

Incremental loading not loading all data

I have implemented incremental loading like this:
public class IncrementalDataSource : ObservableCollection<Files>, ISupportIncrementalLoading
{
private int id;
private int itemsPerPage;
private int currentPage;
public IncrementalMediaEntrySource(int ID, int ipp = 4)
{
HasMoreItems = true;
id = ID;
itemsPerPage = ipp;
currentPage = 1;
}
public bool HasMoreItems
{
get;
private set;
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
var dispatcher = Window.Current.Dispatcher;
return Task.Run<LoadMoreItemsResult>(
async () =>
{
uint resultCount = 0;
var result = await GetData(id, itemsPerPage, currentPage++);
if (result == null || result.Count() == 0)
{
HasMoreItems = false;
}
else
{
resultCount = (uint)result.Count();
await dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
() =>
{
foreach (var item in result)
this.Add(item);
});
}
return new LoadMoreItemsResult() { Count = resultCount };
}).AsAsyncOperation<LoadMoreItemsResult>();
}
}
But it's not loading all data. It only gets around 16 items from 100+ items. If I change itemsPerPage from 4 to 10, it gets all items. But it takes a bit too long to load by 10 items, so I would like to stay with 4 items. And of course I would like to know, what is causing this, to avoid that. Where could be the problem?
UPDATE:
A friend of mine suggested to add "fake" objects, if itemsPerPage is less than 7(minimums number with which it is working correctly), so that total objects recieved would be 7. I tried that, and it actually worked, but of course added empty objects, which is totally useless. So I added check before adding objects to ObservableCollection<Files> like this:
foreach (var item in result)
if (item.Id != null) this.Add(item);
But then it is not working again. So maybe the problem is in adding? But I cannot think of possible cause for this...

Get the largest Value from table unless null

I'm quite new to C# and ASP.NET (and programming in general) and try to do some simple exercises.
What I am trying to do:
I would like to build a simple MVC App where records will have versions.
That is: Given a record, that I am about to change via the "Edit"-View, this record will not be overwritten. Instead a new record will be created (like a new Version). Both, the old and new record, have the same ItemId (which is not the primary key!), that links them together "semantically". In order to know, which record is the newer Version, the newer record has a VersionId that is +1 the VersionId of the older one.
Currently: I've started working on the Create-Action. A new record shall get a value of 1 for it's VersionId and for ItemId the largest ItemId already in the DB plus 1 - unless there is no record in the DB in which case ItemId shall be 1.
The Model:
namespace HowToUpdate.Models
{
public class ItemWithVersion
{
public int Id { get; set; }
public int ItemNr { get; set; }
public int VersionNr { get; set; }
public string Name { get; set; }
}
}
The Controller Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name")] ItemWithVersion itemWithVersion)
{
if (ModelState.IsValid)
{
// set the ItemNr
int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
itemWithVersion.ItemNr = currentMaxItemNr + 1;
// set the VersionNr
itemWithVersion.VersionNr = 1;
db.ItemWithVersions.Add(itemWithVersion);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(itemWithVersion);
}
Problem: When I run localhost/ItemWithVersion/Create, enter a Value for the Name and Submit, i get the following error:
"The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
Source error: int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);"
I tried:
// set the ItemNr
int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
if (currentMaxItemNr == null)
{
itemWithVersion.ItemNr = 1;
}
else
{
itemWithVersion.ItemNr = currentMaxItemNr + 1;
}
Now the error seems to be int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
Also int? currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr); and var currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr); won't do any good.
It's probably basic but I need your help! :) Thx.
Your if-statement is wrong:
if (currentMaxItemNr != null)
currently checks if currentMaxItemNr has a value and if it does, make it 1
So your statement should be if (currentMaxItemNr == null)
Edit:
I can't replicate your error unfortunately, but I did check and found out that there's an exception thrown when calling Max() on an empty List. So it would be better to first call if (db.ItemWithVersions.Count() > 0)
That way you are sure that Max() will return a result. If it fails that statement, you can set currentMaxItemNr to 0
You need to make sure that your table is not empty before calling the Max() method. You can use the Any() method to do that.
int currentMaxItemNr = 0;
if (db.ItemWithVersions.Any())
{
currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr);
}
itemWithVersion.ItemNr = currentMaxItemNr + 1;
// set the VersionNr
itemWithVersion.VersionNr = 1;
db.ItemWithVersions.Add(itemWithVersion);
db.SaveChanges();
Probably, the reason is that Id is declared as a int (not nullable, so null can not be assigned to id) . Try following.
public int? Id { get; set; }
Care to try?
int currentMaxItemNr = db.ItemWithVersions.Max(i => i.ItemNr ?? 1);
This will return currentMaxItemNr = 1 if your i.ItemNr is null.
here is how I would do this. When you click on Edit we run:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name")] ItemWithVersion itemWithVersion)
{
if (ModelState.IsValid)
{
// get the item with highest version
ItemWithVersion item = db.ItemWithVersions.Where(i =>i.ItemNr == itemWithVersion.ItemNr).OrderByDescending(i => i.VersionNr).FirstOrDefault();
//if item doesnt exist we need to create
if(item == null) {
//get the last item with highest ItemNr
ItemWithVersion lastitem = db.ItemWithVersions.OrderByDescending(i => i.ItemNr).FirstOrDefault();
if(lastitem == null) {
//if we didnt find a item, it means is the first item in the DB
itemWithVersion.ItemNr = 1;
} else {
//increment the itemNr for the new Item
itemWithVersion.ItemNr = lastitem.ItemNr + 1;
}
//set version to 1 since is the first version for this new ItemNr
itemWithVersion.VersionNr = 1;
} else {
//if we found a item for the current ItemNr we increase the version for the new item
itemWithVersion.VersionNr = item.VersionNr + 1;
}
db.ItemWithVersions.Add(itemWithVersion);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(itemWithVersion);
}

how to write a recursive function for delete nested folder

I have got a task to delete the hierarchy of folders. When i am deleting a folder, the respective sub folders should be deleted.
public ActionResult DeleteLabel(int id)
{
var query = dbPanAgroDMSContext.LabelMaster.Where(x => x.ParentLabelId == id).ToList();
foreach(var item in query)
{
var query1 = dbPanAgroDMSContext.LabelMaster.Where(x => x.ParentLabelId == item.LabelId).ToList();
dbPanAgroDMSContext.LabelMaster.Remove(item);
foreach (var i in query1)
{
dbPanAgroDMSContext.LabelMaster.Remove(i);
}
}
LabelMaster label = dbPanAgroDMSContext.LabelMaster.Find(id);
dbPanAgroDMSContext.LabelMaster.Remove(label);
dbPanAgroDMSContext.SaveChanges();
return Json(new { Result = "OK" });
}
Instead of using repeated for loops I want to do it in a single block of code.Please help me to create a linq query?
Try this
public ActionResult DeleteLabel(int id)
{
Delete(id);
dbPanAgroDMSContext.SaveChanges();
return Json(new { Result = "OK" });
}
private void Delete(int id)
{
//For given id get all child ones first
var query = dbPanAgroDMSContext.LabelMaster.Where(x => x.ParentLabelId == id).ToList();
foreach(var item in query)
{
//for each child ,delet its' childs by calling recursively
Delete(item.Id);
}
LabelMaster label = dbPanAgroDMSContext.LabelMaster.Find(id);
dbPanAgroDMSContext.LabelMaster.Remove(label);
}

Categories