locked
How to merge and update result RRS feed

  • Question

  • User-1104215994 posted

    Hello,

    I have an asp.net Web API 2 and in one of my action method, I have to return a list of products. There are 2 separate lists, one from my database and the other is returned from a 3rd party rest API. What I would like to do is;

    • There may be the same products within those 2 lists so I would like to find them and update the product stock quantity.
    • And merge the result list and send one as a response

    Here is my database sample response:

    {
        "Products": [
            {
                "ProductID": 6446,
                "ProductName": "400 Riot Points - 400 RP",
                "SmallProductImage": "No Image",
                "SupplierID": 1,
                "GameID": 1,
                "SupplierName": "No Supplier",
                "GameName": "400 Riot Points - 400 RP",
                "Price": 10,
                "IsStockAvailable": true,
                "StockQuantity": 2
            },
            {
                "ProductID": 6447,
                "ProductName": "300",
                "SmallProductImage": "No Image",
                "SupplierID": 1,
                "GameID": 1,
                "SupplierName": "No Supplier",
                "GameName": "300",
                "Price": 5,
                "IsStockAvailable": true,
                "StockQuantity": 2
            },
            {
                "ProductID": 18000006446,
                "ProductName": "400 Riot Points - 400 RP",
                "SmallProductImage": "No Image",
                "SupplierID": 1,
                "GameID": 1,
                "SupplierName": "No Supplier",
                "GameName": "400 Riot Points - 400 RP",
                "Price": 12,
                "IsStockAvailable": true,
                "StockQuantity": 3
            }
        ]
    }

    Here is how I generate my response:

    var productsList = await (context.GameBanks.Where(x => x.used == 0)
                    .GroupBy(g => new
                    {
                        g.productCode,
                        g.productDescription,
                        g.unitPrice,
                        g.used,
                    })
                    .Select(gcs => new
                        {
                            gcs.Key.productCode,
                            gcs.Key.productDescription,
                            gcs.Key.unitPrice,
                            gcs.Key.used,
                            StockQuantity = gcs.Count(),
                            IsStockAvailable = gcs.Count() > 0 ? "True" : "False",
                        }
                    )).ToListAsync();

    Here is 3rd party response:

    {
        "products": [
            {
                "productID": 6440,
                "productCode": "6440",
                "productName": "4500 Kupon",
                "productDescription": "4500 Kupon",
                "smallProductImage": "",
                "supplierID": 0,
                "gameID": 0,
                "supplierName": "",
                "gameName": "",
                "isStockAvailable": false,
                "stockQuantity": 0,
                "commission": 8,
                "sellingPrice": 27.6,
                "payablePrice": "27.60",
                "price": 30,
                "unitPrice": "30.00",
                "currency": "TRY"
            },
            {
                "productID": 6449,
                "productCode": "6449",
                "productName": "3620 Riot Points - 3620 RP",
                "productDescription": "3620 Riot Points - 3620 RP",
                "smallProductImage": "",
                "supplierID": 0,
                "gameID": 0,
                "supplierName": "",
                "gameName": "",
                "isStockAvailable": true,
                "stockQuantity": 10,
                "commission": 6.5,
                "sellingPrice": 89.76,
                "payablePrice": "89.76",
                "price": 96,
                "unitPrice": "96.00",
                "currency": "TRY"
            },
            {
                "productID": 6446,
                "productCode": "6446",
                "productName": "400 Riot Points - 400 RP",
                "productDescription": "400 Riot Points - 400 RP",
                "smallProductImage": "",
                "supplierID": 0,
                "gameID": 0,
                "supplierName": "",
                "gameName": "",
                "isStockAvailable": true,
                "stockQuantity": 10,
                "commission": 6.5,
                "sellingPrice": 11.22,
                "payablePrice": "11.22",
                "price": 12,
                "unitPrice": "12.00",
                "currency": "TRY"
            },
            {
                "productID": 6478,
                "productCode": "6478",
                "productName": "5 TL'lik Steam Cüzdan Kodu",
                "productDescription": "5 TL'lik Steam Cüzdan Kodu",
                "smallProductImage": "",
                "supplierID": 0,
                "gameID": 0,
                "supplierName": "",
                "gameName": "",
                "isStockAvailable": true,
                "stockQuantity": 10,
                "commission": 8,
                "sellingPrice": 4.6,
                "payablePrice": "4.60",
                "price": 5,
                "unitPrice": "5.00",
                "currency": "TRY"
            }
        ],
        "responseStatusCode": "00",
        "version": "V1",
        "signature": "5e7efbcf0c9cb2211d6c783f501b5dc0",
        "applicationCode": "52e7cf966b724749a7c4efadc3727ed7"
    }

    For product 6446, the final response stock quantity should be 12 for this sample. And if there are unmatched products, they are merged into one list. <g class="gr_ gr_55 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del" id="55" data-gr-id="55">May be</g> something like Union removes duplicate products but how can I sum up the stock quantity then.

    productlistA.Union(productlistB).ToList();

    Wednesday, May 22, 2019 6:55 AM

All replies

  • User1724605321 posted

    Hi cenk1536,

    Use Concat, GroupBy and Sum: 

             public class Person {
                public long ProductID { get; set; }
    
    
                public int StockQuantity { get; set; }
    
                public Person() { }
    
                public Person(long productID, int stockQuantity) {
                    this.ProductID = productID;
                    this.StockQuantity = stockQuantity;
                }
    
            }
            public ActionResult Index()
            {
                var personlist1 = new List<Person>();
                personlist1.Add(new Person() { ProductID = 6446, StockQuantity = 2 });
                personlist1.Add(new Person() { ProductID = 6447, StockQuantity = 2 });
                personlist1.Add(new Person() { ProductID = 18000006446, StockQuantity = 3 
                });
    
                var personlist2 = new List<Person>();
                personlist2.Add(new Person() { ProductID = 6440, StockQuantity = 0 });
                personlist2.Add(new Person() { ProductID = 6449, StockQuantity = 10 });
                personlist2.Add(new Person() { ProductID = 6446, StockQuantity = 10 });
                personlist2.Add(new Person() { ProductID = 6448, StockQuantity = 10 });
    
                List<Person> merged = personlist1.Concat(personlist2)
          .GroupBy(so => so.ProductID)
          .Select(g => new Person( g.First().ProductID, g.Sum(so => so.StockQuantity)))
          .ToList();
    
               
            }

    Best Regards,

    Nan Yu

    Thursday, May 23, 2019 2:20 AM
  • User-1104215994 posted

    Hi Nan Yu,

    I will try and let you know.

    Thank you.

    Thursday, May 23, 2019 5:08 AM
  • User-1104215994 posted

    How can I convert 3.party JSON response to a list in order to use your suggestion? Here is how I get response from 3. party.

    var httpClient = new HttpClient();
    
                var keyValues = products.ToKeyValue();
                var content = new FormUrlEncodedContent(keyValues);
    
                var response =
                    await httpClient.PostAsync("https://test.com/Product/", content);
    
    
                var htmlResponse = await response.Content.ReadAsStringAsync();
                var model = JsonConvert.DeserializeObject<ProductsResponse>(htmlResponse);

    Here is ProductResponse entity;

    public class ProductsResponse
        {
            public List<Product> Products { get; set; } = new List<Product>();
        }

    I am getting this;

    {0}Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[EPINMiddleWareAPI.Models.Product]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
    To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
    Path 'Products', line 1, position 12.

    Friday, May 24, 2019 5:33 AM
  • User-1104215994 posted

    This doesn't work because productID is NOT the first one in the list. It was just an example to demonstrate.

     List<Person> merged = personlist1.Concat(personlist2)
          .GroupBy(so => so.ProductID)
          .Select(g => new Person( g.First().ProductID, g.Sum(so => so.StockQuantity)))
          .ToList();

    Saturday, May 25, 2019 12:23 PM
  • User-1104215994 posted

    Here is my merged list as you suggested but it does NOT sum the same product IDs.

    var merged = list1.Concat(list2)
                    .GroupBy(g => new
                    {
                        g.ProductID,
                        g.ProductName,
                        g.Price,
                        g.StockQuantity,
                        g.IsStockAvailable
                    })
                    .Select(gcs => new
                    {
                        gcs.First().ProductID,
                        gcs.Key.ProductName,
                        gcs.Key.Price,
                        StockQuantity = gcs.Sum(so => so.StockQuantity),
                        gcs.Key.IsStockAvailable
                    }).ToList();

    Here is the output which is not what I want.

    [
        {
            "ProductID": 6446,
            "ProductName": "400 Riot Points - 400 RP",
            "Price": 10,
            "StockQuantity": 2,
            "IsStockAvailable": true
        },
        {
            "ProductID": 6447,
            "ProductName": "300",
            "Price": 5,
            "StockQuantity": 2,
            "IsStockAvailable": true
        },
        {
            "ProductID": 18000006446,
            "ProductName": "400 Riot Points - 400 RP",
            "Price": 12,
            "StockQuantity": 3,
            "IsStockAvailable": true
        },   
        {
            "ProductID": 6449,
            "ProductName": "3620 Riot Points - 3620 RP",
            "Price": 96,
            "StockQuantity": 10,
            "IsStockAvailable": true
        },
        {
            "ProductID": 6446,
            "ProductName": "400 Riot Points - 400 RP",
            "Price": 12,
            "StockQuantity": 10,
            "IsStockAvailable": true
        },
        {
            "ProductID": 6478,
            "ProductName": "5 TL'lik Steam Cüzdan Kodu",
            "Price": 5,
            "StockQuantity": 10,
            "IsStockAvailable": true
        }
    ]

    Sunday, May 26, 2019 11:21 AM
  • User-1104215994 posted

    Is there a way to just group by ProductID but I need to select the ProductName, Price StockQuantity and IsStockAvailable as well?

    Sunday, May 26, 2019 4:25 PM
  • User1724605321 posted

    Hi cenk1536,

    The same as code sample provided above :

      public class Person {
                public long ProductID { get; set; }
    
                public string ProductName { get; set; }
    
                public string Price { get; set; }
    
                public int StockQuantity { get; set; }
    
                public Person() { }
    
                public Person(long productID, int stockQuantity ,string productName,string price) {
                    this.ProductID = productID;
                    this.StockQuantity = stockQuantity;
                    this.ProductName = productName;
                    this.Price = price;
                }
    
            }
            public ActionResult Index()
            {
                var personlist1 = new List<Person>();
                personlist1.Add(new Person() { ProductID = 6446, StockQuantity = 2 ,ProductName= "400 Riot Points - 400 RP",Price="10" });
                personlist1.Add(new Person() { ProductID = 6447, StockQuantity = 2, ProductName = "No Image", Price = "5" });
                personlist1.Add(new Person() { ProductID = 18000006446, StockQuantity = 3, ProductName = "400 Riot Points - 400 RP", Price = "12" });
    
                var personlist2 = new List<Person>();
                personlist2.Add(new Person() { ProductID = 6440, StockQuantity = 0 , ProductName = "4500 Kupon", Price = "30" });
                personlist2.Add(new Person() { ProductID = 6449, StockQuantity = 10 , ProductName = "3620 Riot Points - 3620 RP", Price = "96" });
                personlist2.Add(new Person() { ProductID = 6446, StockQuantity = 10 , ProductName = "400 Riot Points - 400 RP", Price = "12" });
                personlist2.Add(new Person() { ProductID = 6478, StockQuantity = 10 , ProductName = "5 TL'lik Steam Cüzdan Kodu", Price = "5" });
    
                List<Person> merged = personlist1.Concat(personlist2)
          .GroupBy(so => so.ProductID)
          .Select(g => new Person(g.First().ProductID, g.Sum(so => so.StockQuantity),g.First().ProductName,g.First().Price))
          .ToList();
    
                return View();
            }

    Best Regards,

    Nan Yu

    Monday, May 27, 2019 2:04 AM