Click here to Skip to main content
15,885,216 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi there,

I am working with an API which provides me with the following collection:
C#
Dictionary<string,list<product>>


The key is the Product Code and the value is a list contains the actual Product object.

The Product entity in the C# application contains the following properties:
Product_ID
Product_NAME
Product_DESC
Product_CODE
Product_TYPE


Product_TYPE entity in the C# application is a complex type and contains the following properties:
Product_TYPE_CODE
Product_TYPE_DESC


The Product_Code and Product_Type can be null because those columns in the database are can be set to null as well.

The end user in my application provides a list of Product_codes and/or Product_types. Now regarding the ProductType List, if the value is "UNKNOWN" i would like to match that value on the null value for that particular property and substitute it for "UNKNOWN".

So say i have list of ProductTypes and the list contains value of "UNKNOWN" i want to match that on the ProductType property of the C# entity.

How can i go about doing this using LINQ?

I appreciate assistance/advice regarding the above.

What I have tried:

I tried the following code which comes from the API but i am having difficulty using LINQ to filter the products out using the provided List of ProductTypes and ProductCodes and substitute the ProductType property:

var loadedProducts = ProductFactory.GetAll();

This method essentially gets the products from the db and caches them appropriately. The return value from invoking this method is
C#
Dictionary<string,list<product>>()


Is LINQ appropriate to use in this context or is it not a good idea to use LINQ?

I can filter the Products by PRODUCT_CODE and PRODUCT_TYPE by doing the following in SQL(this is still in work in progress but i wanted to demonstrate what i can do so far in SQL).

C#
SELECT PRODUCT_ID,
 PRODUCT_CODE,
COALESCE(PRODUCT_TYPE, 'UNKNOWN') as PRODUCT_TYPE,
PRODUCT_DESC,
FROM PRODUCTS
WHERE PRODUCT_CODE IN ('TYAHAH','ABH989')
AND COALESCE(PRODUCT_TYPE, 'UNKNOWN') IN ('ABC','UNKNOWN');
Posted
Updated 20-Oct-16 22:50pm
v3
Comments
Midi_Mick 19-Oct-16 7:48am    
You can almost certainly do what you want with linq - I'm just not sure what you are expecting as a result. You have your Dictionary which has a value that is a list of products. Given your input, are you just after a single list of products garnered from all the lists, or are you after a list of keys that have an associated list of products that match your input, or maybe a list of lists, each of which contain a product that meets your criteria?
Also - you say that your Dictionary's key is the PRODUCT_CODE, and PRODUCT_CODE can be null. It is not permissible to have a dictionary key of null, so I assume you've already translated that to "UNKNOWN" before you create the dictionary.
Eagle32 19-Oct-16 10:08am    
Apologies, i have updated my actual problem and my SQL.
I have checked the API, the Product_Code is actually always populated in the database and will contain a real value (i.e not "UNKNOWN") and the Product_Type is not always populated with an actual value.

What i would like to do is filter the dictionary collection and return just a List<products>. I want to filter using the user provided ProductCodes List and the ProductTypes List.

I want to match on the ProductCode using the ProductCodeList provided by the end user. This list will never contain "UNKNOWN".

Now regarding user providedlist called ProductTypes List, if the value contains "UNKNOWN", i want to match on the null value of the ProductType property of the Product that exist in that List<product> in the Dictionary i mentioned. I then want to replace the null value of the property with "UNKNOWN".
BillWoodruff 19-Oct-16 8:42am    
Confusing: you talk about a .NET Dictionary, you talk about LIsts.

Please clarify exactly what the result you want to achieve is. Are you asking about how to create a query to the database that returns a dataset of the "complex objects," or, are you asking about taking a .NET Dictionary as your "source," and doing something to that using Linq. Why have you shown the SQL query code ? Where do the "Lists" come from. Did you create the Classes you describe ?
Eagle32 19-Oct-16 9:58am    
Apologies, I have updated my actual problem and my SQL. I have looked at the API i am working with and the ProductCode in the Products table is always populated and therefore never null.

However ProductType can be null and the data i am working with have several entries which the ProductType is NULL. I want to match on this value and if the value is NULL and the value in the user provided list called ProductTypes is "UNKNOWN" i want to replace the value of the ProductType where the value is NULL which exists in the Dictionary<string, list<product="">> with "UNKNOWN".

I am asking how would i filter the data that i get back based on the user provided inputs where the return value's data structure is of the following format Dictionary<string, list<product="">>();

C#
// Assuming these are populated (or at very least, Instantiated with no elements)
List<string> userProductCodes;
List<string> userTypeCodes;

Dictionary<string, list<product="">> loadedProducts;

List<string> matchingList = loadedProducts
	.Where(kv=>userProductCodes.Contains(kv.Key)) // Selects only items where the key is in the userProductCodes list
	.Select(kv=>kv.Value) // separates out the value of the Key/Value pairs (i.e. the lists), so we now have a list of lists that have an appropriate PRODUCT_CODE
	.Aggregate(new List<string>(), (newList, oldList)=>{ newList.AddRange(oldList); return newList;}) // Now we have combined all the lists into one single big list
	.Where (product=>userTypeCode.Contains(product.TYPE_CODE ?? "UNKNOWN")) // Match the User Type codes up - replaces null with "UNKNOWN" for the check
	.ToList(); // Converts the result to a list.


Note: This is an "AND" type result i.e. The Products where the Product code is in the user list AND the type code is in the user Type list.
To make an OR type list, remove the line that selects the product code from the key/value pairs, and extend the Where that selects the type code so that is has an "|| userProductCode.Contains(product.PRODUCT_CODE)" as its condition.
 
Share this answer
 
v3
Comments
Eagle32 21-Oct-16 4:16am    
Thanks, Now instead of a List of Products in the dictionary if i have just a Dictionary<string, product=""> how would i achieve the above i.e filtering and converting to a list?
Midi_Mick 21-Oct-16 4:38am    
Putting your answer in a Solution so it can be formatted...see below (in a few minutes)
This makes it much simpler - and there are 2 approaches. There will only be one Where in the entire thing. You can either use the key to check the PRODUCT_CODE, or just process the values and check for both product and type codes there.

Option 1:
C#
loadedProducts.Where(kv=>userProductCodes.Contains(kv.Key) && userTypeCodes.Contains(kv.Value.TYPE_CODE ?? "UNKNOWN")

or, just using the values collection
C#
loadedProducts.Values.Where(product=>userProductCodes.Contains(product.PRODUCT_CODE) && userTypeCodes.Contains(product=>product.TYPE_CODE ?? "UNKNOWN")


Once again, the above returns record where both parameters are true (i.e. Both PRODUCT_CODE and TYPE_CODE occur in respective lists). Just change the && to || if you want results where either are true.

Actually, this question was part of the inspiration of the latest Tip/Trick article I wrote - have a read of it, it may help you understand just how to achieve this sort of thing for yourself.
Finding Items in a Collection that Match one of...[^]
 
Share this answer
 
v2
Comments
Eagle32 21-Oct-16 5:48am    
At which point do i invoke .ToList() method so i get just a List<product> at the end.
Midi_Mick 21-Oct-16 6:05am    
Yes - at end. Both the above produce an IEnumerable<string>, which can be converted to a list, array, or even a few other more complex containers.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900