C# LINQ sub-where - c#

I have object
public class OrderItem
{
public string idProduct { get; set; }
public int quantity { get; set; }
public List<WarehouseItem> WarehouseInfo = new List<WarehouseItem>();
}
public class WarehouseItem
{
public string Name{ get; set; }
public string LocnCode{ get; set; }
}
and i need select items which have WarehouseInfo.LocnCode == "A1"
It is doesnt work when I use something like
var items = itemList.Where(x => x.WarehouseInfo.Where(y => y.LocnCode.Equals("A1")));

Your requirements could be interpreted one of three ways, so here's three solutions:
Give me all OrderItems where ANY WarehouseItem has a LocnCode of "A1":
var items = itemList.Where(i => i.WarehouseInfo.Any(w => w.LocnCode == "A1"));
Give me all WarehouseItems within the OrderItems that have a LocnCode of "A1":
var items = itemList.SelectMany(i => i.WarehouseInfo)
.Where(w => w.LocnCode.Equals("A1"));
Give me all OrderItems where ANY WarehouseItem has a LocnCode of "A1", and filter WarehouseInfo to only those WarehouseItems:
This can't be done in a simple Linq query because there's no way to change the contents of the existing objects. You're going to have to create new objects with the filtered values:
var items = itemList.Where(i => i.WarehouseInfo.Any(w => w.LocnCode == "A1"))
.Select(i => new OrderItem
{
idProduct = i.idProduct,
quantity = i.quantity,
WarehouseInfo = i.WarehouseInfo.Where(w => w.LocnCode.Equals("A1"));
.ToList()
}
);

Try
var items = itemList.Where(x => x.WarehouseInfo.Any(y => y.LocnCode.Equals("A1")));
The Where takes a predicate that should return a bool. Any will return true if at least one item in the collection returns true for the given predicate.

Related

Get selected fields on a list using a LINQ query

I have an entity framework generated class like this.
public partial class TBLM_PRODUCT
{
public string PRODUCT_CODE { get; set; }
public string PRODUCT_DESC { get; set; }
public string PRODUCT_ISBN { get; set; }
public string PRODUCT_SUPPLIER { get; set; }
public string PRODUCT_PROGROUP { get; set; }
}
Normally I select items list like this using a LINQ query.
using ( AEntities RAEntity = new AEntities())
{
RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
}
I want to select an item list with two fields like this like as in following query
select PRODUCT_CODE,PRODUCT_DESC from TBLM_PRODUCT where PRODUCT_PROGROUP='GG';
How can I achieve that?
using ( AEntities RAEntity = new AEntities())
{
var all = RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
var yourList = all
.Where(x => x.PRODUCT_PROGROUP == "GG")
.Select(p => new { p.PRODUCT_CODE, p.PRODUCT_DESC })
.ToList();
}
Don't select all records first and then filtered your data.
If you use .ToList<DataControllers.TBLM_PRODUCT>() then it can select all records. So instead of this you can select your columns at the time of query fired to database.
If your TBLM_PRODUCT is of any collection type like IEnumerable<> or IQueryable<> then,
using ( AEntities RAEntity = new AEntities())
{
var result = RAEntity.TBLM_PRODUCT.Where(x => x.PRODUCT_PROGROUP == "GG").Select(x => new { x.PRODUCT_CODE, x.PRODUCT_DESC }).ToList();
}
using (AEntities RAEntity = new AEntities())
{
var list= RAEntity.TBLM_PRODUCT
.Where(p => p.PRODUCT_PROGROUP == "GG")
.Select(p => new TBLM_PRODUCT { PRODUCT_CODE = p.PRODUCT_CODE, PRODUCT_DESC = p.PRODUCT_DESC })
.ToList();
}

LINQ how to Filter the data based on the value of the properties

i have a problem with filtering data in LINQ , here is my Model :
public class CoursePlan
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Semester { get; set; }
public string ModuleCode { get; set; }
public string ModuleName { get; set; }
public string Credits { get; set; }
public string OrderNumber { get; set; }
public string ModuleStatus { get; set; }
}
and here is my data Json
the problem here some modules having same OrderNumber which mean they are optional , student must study one of them and if student already study one of them , i should ignore other modules in same order number.
in other way to describe the question
i want to return a list of CoursePlan and on this list if there is two items having same OrderNumber check the ModuleStatus for each one of them and if any one is Completed remove other modules on that order otherwise return them all .
here is my code
var coursePlanList = await _sqLiteAsyncConnection.Table<CoursePlan>().ToListAsync();
var groupedData = coursePlanList.OrderBy(e => e.Semester)
.GroupBy(e => e.OrderNumber)
.Select(e => new ObservableGroupCollection<string, CoursePlan>(e))
.ToList();
for now im solving this by this algorithm and not sure if it's the best
var coursePlanList = await _sqLiteAsyncConnection.Table<CoursePlan>().ToListAsync();
List<CoursePlan> finalList = new List<CoursePlan>();
var counter = 0;
foreach (var itemPlan in coursePlanList)
{
if (counter > 0 && counter < coursePlanList.Count)
if (itemPlan.OrderNumber == coursePlanList[counter - 1].OrderNumber)
{
if (itemPlan.ModuleStatus == "Completed")
{
finalList.RemoveAll(a => a.OrderNumber == itemPlan.OrderNumber);
finalList.Add(itemPlan);
}
Debug.WriteLine(itemPlan.ModuleName + "With -->" + coursePlanList[counter - 1].ModuleName);
}
else
finalList.Add(itemPlan);
counter++;
}
var groupedData = finalList.OrderBy(e => e.ModuleStatus)
.ThenBy(e => e.Semester)
.GroupBy(e => e.Semester)
.Select(e => e)
.ToList();
CoursePlanViewList.BindingContext = new ObservableCollection<IGrouping<string, CoursePlan>>(groupedData);
Any advise or guidance would be greatly appreciated
Let me rephrase your requirement: you want to show all plans per OrderNumber that meet the condition: none of the plans in their group should be "Completed" or the plans themselves should be "Completed". All this grouped by Semester:
var plansQuery =
from p in _sqLiteAsyncConnection.Table<CoursePlan>()
group p by p.Semester into sem
select new
{
PlansInSemester =
from p in sem
group p by p.OrderNumber into gp
select new
{
PlansInOrderNumber =
gp.Where(p => !gp.Any(p1 => p1.ModuleStatus == "Completed")
|| p.ModuleStatus == "Completed")
}
};
This gives you an IQueryable that produces the course plans you want to select, but grouped in two levels, so the final result is obtained by flattening the query twice:
var coursePlanList = await plansQuery
.SelectMany(x => x.PlansInSemester
.SelectMany(y => y.PlansInOrderNumber)).ToListAsync()

Where clause on list property

I have two classes :
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Product> Product { get; set; }
}
public class Product
{
public string ProductNumber { get; set; }
public string ProductColor { get; set; }
}
I want to create a clause where on property Product (Product.ProductColor == "") I do :
c.Where(x => x.Product.????? == "11").Select(x => x).ToList();
How do this ?
I assume you want to find customers, that have a product with Number 11. If so, you can use function Any:
var result = c
.Where(x => x.Product.Any(p => p.ProductNumber == "11"))
.ToList();
The code filters only those customers, that have at least one product that satisfies condition ProductNumber == "11"
Or if you want to find customers that have specific color then use different expression:
var result = c
.Where(x => x.Product.Any(p => p.ProductColor == "Color"))
.ToList();
Since Product (which really should be named Products) is also a collection, you'd have to drill down into that collection. For example, if you want all Customers from a list of customers where any product color is "11", it might looks like this:
customers.Where(c => c.Product.Any(p => p.ProductColor == "11"))

LINQ to Entities, Where Any In

How to write 'Where Any In' in LINQ to Entity?
Here is my model :
class Chair
{
public int Id { get; set; }
public int TableId { get; set; }
public Table Table { get; set; }
}
class Table
{
public int Id { get; set; }
public ICollection<Chair> Chairs { get; set; }
public ICollection<Category> Categories { get; set; }
public Table()
{
Chairs = new List<Chair>();
Categories = new List<Category>();
}
}
class Category
{
public int Id { get; set; }
public ICollection<Table> Tables { get; set; }
}
I also got a simple list of Category :
List<Category> myCategories = new List<Category>(c,d,e);
I want to get only that Chairs that belongs to Table that got one of the Category from myCategories List. Thats what im trying to do :
var result =
ctx.Chairs.Where(x => x.Table.Categories.Any(y => myCategories.Any(z => z.Id == y.Id))).ToList();
I think its ok but what i get is error :
"Unable to create a constant value of type 'ConsoleApplication1.Category'. Only primitive types or enumeration types are supported in this context"
Try to compare with in-memory categories Ids collection, instead of categories collection.
var myCategoriesIds = myCategories.Select(c => c.Id).ToArray();
var result =
context.Chairs
.Where(
x => x.Table.Categories.Any(
y => myCategoriesIds.Contains(y.Id)))
.ToList();
this is because ctx.Chairs is a collection that is in database, you should retrieve that collection first in order to compare it with in-memory data:
var result = ctx
.Chairs
.AsEnumerable() // retrieve data
.Where(x =>
x.Table.Categories.Any(y =>
myCategories.Any(z => z.Id == y.Id)))
.ToList();
EDIT: that wouldn't be the correct thing to do if you have a lot of entities on database, what you can do is to split it into two queries:
var tables = ctx.Tables
.Where(x =>
x.Categories.Any(y =>
myCategories.Any(z => z.Id == y.Id)));
var result = ctx.Chairs
.Where(x =>
tables.Any(t=> t.Id == x.TableId))
.ToList();
You can select Ids from myCategories and use it last statement.
var CategoryIds = myCategories.Select(ct => ct.Id);
var result = ctx.Chairs.Where(x => x.Table.Categories.Any(y => CategoryIds.Any(z => z == y.Id))).ToList();

How to sort a C# list of data where the data is a hierarchical tree (menu)?

I'm pulling a dataset into a c# list and to sort it. It's a hierarchical menu:
sample object:
public class NavigationInfo
{
public Int32 Id { get; set; }
public Int32 ParentId { get; set; }
public String Text { get; set; }
public String Url { get; set; }
public Int32 Sort { get; set; }
}
The ParentId is recursive to Id and Sort is an ascending integer within the ParentId. How is that done using a collection of NavigationInfo in List<NavigationInfo>?
You can do something like:
var navigationInfos = new List<NavigationInfo>(); //fill this collection
navigationInfos.sort((a,b) => a.Id.CompareTo(b.Id)); //sort by Id
navigationInfos.sort((a,b) => a.ParentId.CompareTo(b.ParentId)); //sort by ParentId
UPDATE: You can also use LINQ and do an OrderBy on the List. This returns a new collection, but is a lot easier to order by multiple criteria, ascending or descending.
var navigationInfos = new List<NavigationInfo>(); //fill this collection
var listSortedById = navigationInfos
.OrderBy(n => n.Id).ToList();
var listSortedByParentId = navigationInfos
.OrderBy(n => n.ParentId).ToList();
var listSortedByIdThenByParentId = navigationInfos
.OrderBy(n => n.Id)
.ThenBy(p => p.ParentId)
.ToList();
var orderedByIdDescending = navigationInfos
.OrderByDescending(n => n.Id)
.ToList();
If the data comes from DB, you can let the DB send the output in sorted manner (parent first, followed by child Id).
Note: I am assuming DB has the Ids in an order where parent will be a lesser Id than a child.
If your hierarchy will be more than a simple two-level arrangement, you'll need to write a method (probably recursive) that can travel up the tree collecting the entire "path" of each item's ids. Once you have this path, the sorting step is fairly easy.
Add a property to NavigateInfo
public string ItemPath { get; set; }
Then use a method like this to set that property.
public string GetPath(List<NavigationInfo> list, int itemId)
{
NavigationInfo item = list.SingleOrDefault(x => x.Id == itemId);
if (item == null)
{
return "";
}
else
{
return GetPath(list, item.ParentId) + "\\" + itemId;
}
}

Categories