Avatar billede ReneDahl Praktikant
15. maj 2016 - 22:53 Der er 18 kommentarer og
1 løsning

ASP.NET MVC appikation - Shoppingcart.

Hej Folkens, nogen der ud fra koden hurtig kan komme med lidt feedback. Jeg har fulgt en tutorial på youtube på hvordan man opsætter en indkøbskurv i MVC ved hjælp af sessions.

Mit problem opstår i Delete metoden, hvor jeg forsøger at fjerne items fra en Liste (List). Men af en eller anden grund fjerne den alle items frem for en af gangen.

Tror lidt problemet ligger i at der mangler et loop enten for eller foreach. Men kan ikke helt finde ud af det.

Men her er eksempel på alt min kode fra controlleren.

<code>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Outlet.Models.Database;

namespace Outlet.Controllers
{
    public class ShoppingCartController : Controller
    {
        public Connection db = new Connection();

        // GET: Cart
        public ActionResult Index()
        {
            return View();
        }

        private int isExisting(int id)
        {
            List<Item> cart = (List<Item>)Session["cart"];

            for (int i = 0; i < cart.Count; i++)
                if (cart[i].Product.productId == id)
                    return i;
            return -1;
        }

        public ActionResult Delete(int id)
        {
            int index = isExisting(id);
            List<Item> cart = (List<Item>)Session["cart"];
            cart.RemoveAt(index);



            //var lstSlet = cart.Where(x => x.Product.productId == id);
            //cart.ForEach(x => cart.Remove(x));
            Session["cart"] = cart;

            return View("Cart");
        }
       
        public ActionResult OrderNow(int id)
        {
            if (Session["cart"] == null)
            {
                List<Item> cart = new List<Item>();
                cart.Add(new Item(db.Products.Find(id), 1));
                Session["cart"] = cart;
            }

            else
            {
                List<Item> cart = (List<Item>)Session["cart"];
                int index = isExisting(id);
                if (index == -1)
                    cart.Add(new Item(db.Products.Find(id), 1));
                else
                    cart[index].Quantity++;
                Session["cart"] = cart;

            }
            return View("Cart");
        }
    }
}

</code>
Avatar billede ReneDahl Praktikant
15. maj 2016 - 22:54 #1
Avatar billede softspot Forsker
16. maj 2016 - 00:20 #2
Som jeg skrev i webudvikler-gruppen på facebook, så kunne du anvende en foreach (som jeg kan se du har forsøgt at replikere, men ændret på, så den ikke fungerer :-)).

var lstSlet = cart.Where(x => x.Product.productId == id);
cart.ForEach(x => cart.Remove(x));


skal i stedet være

var lstSlet = cart.Where(x => x.Product.productId == id);
lstSlet.ForEach(x => cart.Remove(x));


Det er muligt, at du skal kalde .ToList() på cart.Where, altså

var lstSlet = cart.Where(x => x.Product.productId == id).ToList();


men prøv lige uden først.

Grunden til at du gemmer de produkter der skal slettes i en ny liste er, at du ikke kan gennemløbe en liste samtidig med at du sletter elementer i den samme liste. Derfor kopierer du referencerne til de objekter der skal slettes over i en ny liste. Den nye liste kan så gennemløbes, mens du sletter objekterne i den oprindelige liste.

Din Delete burde kunne klares med flg.:

public ActionResult Delete(int id)
{
    var cart = (List<Item>)Session["cart"];

    var lstSlet = cart.Where(x => x.Product.productId == id);
    lstSlet.ForEach(x => cart.Remove(x));

    Session["cart"] = cart;

    return View("Cart");
}
Avatar billede arne_v Ekspert
16. maj 2016 - 05:02 #3
Hvad med:

cart = cart.Where(x => x.Product.productId != id).ToList();

?
Avatar billede softspot Forsker
16. maj 2016 - 08:31 #4
Hehe! Narturligvis, arne!
Avatar billede ReneDahl Praktikant
16. maj 2016 - 12:16 #5
Fedt tak for feedback, det lidt ligesom en nål i en høstak. Så det var dejligt med andre øjne på det. Var ved at køre død i det.

Jeg prøver lige at se om jeg kan få det til at virke, men tak for jeres feedback. :0)
Avatar billede ReneDahl Praktikant
16. maj 2016 - 12:35 #6
Nu ser det godt nok ud til den fjerne alle items fra Listen. Det er ikke helt det den skal.


  var cart = (List<Item>)Session["cart"];

            var lstSlet = cart.Where(x => x.Product.productId == id).ToList();
            lstSlet.ForEach(x => cart.Remove(x));

            Session["cart"] = cart;

            return View("Cart");
Avatar billede ReneDahl Praktikant
16. maj 2016 - 12:50 #7
Jeg har nu også forsøgt med et for loop, hmm

  public ActionResult Delete(int id)
        {
            int index = isExisting(id);
            List<Item> cart = (List<Item>)Session["cart"];

            for (int i = cart.Count - 1; i >= 0; i--)
            {
                cart.RemoveAt(i);
            }
              // cart.RemoveAt(index);

            //var lstSlet = cart.Where(x => x.Product.productId == id);
            //cart.ForEach(x => cart.Remove(x));
            Session["cart"] = cart;

            return View("Cart");


        }
Avatar billede softspot Forsker
16. maj 2016 - 13:55 #8
I din egen version sletter du jo netop alle elementer, så den gør det du beder den om ;-)

Umiddelbart virker det som om, at alle produkter i din liste har det samme id og at det så er derfor alt bliver slettet. Du skal starte med, at sikre dig, at dit datagrundlag er som det skal være.

Du bør nok anvende Arnes udgave, da den er mere direkte til opgaven, men princippet i både Arnes og min løsning, er det du har brug for.
Avatar billede ReneDahl Praktikant
16. maj 2016 - 14:05 #9
Ja det fandt jeg ud af,  men det er nu mere antal (quantity) jeg vil have slette, hvor mange stk af hver vare.
Avatar billede softspot Forsker
16. maj 2016 - 15:12 #10
OK, men det er jo en anden opgave end at slette den enkelte vare fra kurven (med mindre der ikke er flere tilbage på varelinjen).

Jeg tror der er behov for, at du beskriver helt præcis, hvad det er du vil opnå og hvilken datamodel du arbejder med. Det er umuligt at hjælpe effektivt, hvis man selv skal sidde og gætte sig frem til en masse parametre.
Avatar billede softspot Forsker
16. maj 2016 - 15:16 #11
Hvis du med Delete blot vil fratrække én enhed fra varelinje med det oplyste id, kunne det være noget i stil med dette:

var vare = cart.FirstOrDefault(l => l.ProductId == id);
if(vare != null)
{
  if(vare.Quantity > 1)
    vare.Quantity--;
  else
    cart.Remove(vare);
}
Avatar billede ReneDahl Praktikant
16. maj 2016 - 15:49 #12
Jeg benenytter mig af EntityFramework, hvor til jeg har oprettet følgende klasser til hvor jeg har en proptity "quantity" som skal tage højde for antal stk man lægger i.

Første klasser her er item, som ligger i mit controllerlag.

*--name spaces--*

namespace Outlet.Controllers
{
    public class Item
    {
        private Product product = new Product();
        private int quantity;

        public Item()
        {

        }

        public Item(Product product, int quantity)
        {
            this.Product = product;
            this.Quantity = quantity;
        }

        public Product Product
        {
            get{ return product; }
            set{ product = value; }
        }

        public int Quantity
        {
            get{ return quantity; }
            set{ quantity = value; }
        }
    }
}

Efterfølgende har jeg også ShoppingCartController hvor delete metoden  ligger i.

*--name spaces--*


namespace Outlet.Controllers
{
    public class ShoppingCartController : Controller
    {
        public Connection db = new Connection();

        // GET: Cart
        public ActionResult Index()
        {
            return View();
        }

        private int isExisting(int id)
        {
            List<Item> cart = (List<Item>)Session["cart"];

            if(cart.Count > 0)
            {
                for (int i = 0; i < cart.Count; i++)
                    if (cart[i].Product.productId == id)
                        return i;
             
            }

            if (cart.Count < 0)
            {
                for (int i = 0; i < cart.Count; i--)
                    if (cart[i].Product.productId == id)
                        return i;
            }
         

            return -1;
        }

        public ActionResult Delete(int id)
        {
            int index = isExisting(id);
            List<Item> cart = (List<Item>)Session["cart"];

           

            for (int i = cart.Count - 1; i >= 0; i--)
            {
           
               
             
                cart.RemoveAt(i);
            }
              // cart.RemoveAt(index);

            //var lstSlet = cart.Where(x => x.Product.productId == id);
            //cart.ForEach(x => cart.Remove(x));
            Session["cart"] = cart;

            return View("Cart");


        }
       
        public ActionResult OrderNow(int id)
        {
            if (Session["cart"] == null)
            {
                List<Item> cart = new List<Item>();
                cart.Add(new Item(db.Products.Find(id), 1));
                Session["cart"] = cart;
            }

            else
            {
                List<Item> cart = (List<Item>)Session["cart"];
                int index = isExisting(id);
                if (index == -1)
                    cart.Add(new Item(db.Products.Find(id), 1));
                else
                    cart[index].Quantity++;
                Session["cart"] = cart;

            }
            return View("Cart");
        }
    }
}

Det jeg vil have er at antal stk (quantity) minimeres når man klikker delete, frem for sådan det er nu, hvor den bare sletter alt i listen.
Avatar billede softspot Forsker
16. maj 2016 - 16:17 #13
Prøv lige mit sidste post, dog med denne rettelse (produktid fra produktet):

var vare = cart.FirstOrDefault(l => l.Product.ProductId == id);
if(vare != null)
{
  if(vare.Quantity > 1)
    vare.Quantity--;
  else
    cart.Remove(vare);
}
Avatar billede ReneDahl Praktikant
16. maj 2016 - 16:28 #14
Fedt, jeg prøver det lige af senere. Er lige ved at refactor noget kode :0)
Avatar billede ReneDahl Praktikant
16. maj 2016 - 18:25 #15
Det virker nu, tak for hjælpen ! :0)

public ActionResult Delete(int id)
        {
            int index = isExisting(id);
            List<Item> cart = (List<Item>)Session["cart"];

            Item item = cart.FirstOrDefault(l => l.Product.productId == id);

            for (int i = cart.Count - 1; i >= 0; i--)
            {
               

                if (item != null)
                {
                    if (item.Quantity > 1)
                        item.Quantity--;
                    else
                        cart.RemoveAt(i);
                }
             
            }

            Session["cart"] = cart;

            return View("Cart");


        }
Avatar billede ReneDahl Praktikant
16. maj 2016 - 18:26 #16
Tak, jeg fik det til at virke :0)
Avatar billede arne_v Ekspert
16. maj 2016 - 19:53 #17
og du tog selv point fordi du ikke mener at du har faet hjaelp????
Avatar billede ReneDahl Praktikant
16. maj 2016 - 19:55 #18
Nej jeg fatter ikke helt, hvordan de point fungere, jeg ville bare lukke tråden :0)
Avatar billede softspot Forsker
16. maj 2016 - 20:21 #19
Velbekomme.

Jeg forstår nu ikke helt alt den kode du har i din Delete. Det virker overflødig at tjekke på om den eksisterer (isExisting), samt din løkke omkring sletningen/nedskrivningen af varelinjen.

Dette burde være længe rigelig:

public ActionResult Delete(int id)
{
    List<Item> cart = (List<Item>)Session["cart"];

    Item item = cart.FirstOrDefault(l => l.Product.productId == id);

    if (item != null)
    {
        if (item.Quantity > 1)
            item.Quantity--;
        else
            cart.RemoveAt(i);
    }

    return View("Cart");
}


Den sidste tildeling til Session burde heller ikke være nødvendig, da du arbejder med en reference til et objekt der allerede ligger i session. Du kunne i det mindste prøve at se om det fungerer uden, inden du sætter den ind.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester