How to multi columns group linq in c# - linq

I have list as below:
Health_Plan HealthMemberType_Name Health_Benefit_Description
Silver Parent a1
Silver Spouse b1
Silver Children c1
Silver Parent a2
Silver Spouse b2
Silver Children c2
Gold Parent a1
Gold Spouse b1
Gold Children c1
Gold Parent a2
Gold Spouse b2
Gold Children c2
I expect to get the following result, (group by Health_Plan and HealthMemberType_Name)
Silver
Parent
a1
a2
Spouse
b1
b2
Children
c1
c2
Gold
Parent
a1
a2
Spouse
b1
b2
Children
c1
c2
tried codes below:
var _aBenefits = _lHealthBenefit.GroupBy(o1 => new { o1.Health_Plan_Pid, o1.Health_Plan }).Select(grp1 => new Health_Benefits_Consolidated
{
Health_Plan_Pid = grp1.Key.Health_Plan_Pid,
Health_Plan = grp1.Key.Health_Plan,
Health_Benefits = grp1.ToList()
}).ToList();
public class Health_Benefits
{
public long Health_Plan_Pid { get; set; }
public string Health_Plan { get; set; }
public string Health_Benefit_Description { get; set; }
public double Health_MaxLimit { get; set; }
public string HealthMemberType_Name { get; set; }
public string CCY { get; set; }
public int Max_Member { get; set; }
}
public class Health_Benefits_Consolidated
{
public long Health_Plan_Pid { get; set; }
public string Health_Plan { get; set; }
public int Max_Member { get; set; }
public List<Health_Benefits> Health_Benefits { get; set; }
}
looks like I have to group "HealthMemberType_Name" into List.. but I don't know how to insert group to "Health_Benefits = grp1.ToList()"
any help appreciated..
thanks a lot in advance
Regards
Don

So you want to group your input items into groups of input items that have the same HealthPlan.
The elements of each group must be grouped into subgroups, where every element of a subgroup has the HealthMemberTypeName.
The elements of each subgroup are the HealthBenefitDescriptions of this Group - SubGroup
For this we use a GroupBy inside another GroupBy. We use the Enumerable.GroupBy overload that has a resultSelector
var results = myInputSequence.GroupBy(
// parameter KeySelector: make groups of inputItems that have equal HealthPlan
inputItem => inputItem.HealthPlan,
// parameter resultSelector: take the common HealthPlan, and all input items
// that have this Healthplan to make a new object:
(healthPlan, inputItemsWithThisHealthPlan) => new
{
HealthPlan = healthPlan,
// Subgroups: take all input items with this healthplan, and group by
// HealthMemberTypeName
HealthMembers = inputItemsWithThisHealthPlan.GroupBy(
// keySelector:
inputItemWithThisHealthPlan => inputItemWithThisHealthPlan.HealthMemberTypeName,
// ResultSelector: take the common HealthMemberTypeName and all
// input items with this HealthPlan and this HealthMemberTypeName
// to make one new object
(healthMemberTypeName, inputItemsWithThisHealthMemberTypeName) => new
{
HealthMemberTypeName = healthMemberTypeName,
// keep only the HealthBenefitDescriptions:
HealthBenefitDescriptions = inputItemsWithThisHealthMemberTypeName
.Select(inputItemWithThisHealthMemberTypeName => inputItemsWithThisHealthMemberTypeName.HealthBenefitDescription)
.ToList(),
})
.ToList(),
});
The long identifier names might make it difficult to read, but I thought it would help you to understand better what is in it than if I had used x, y, z. Plurals are sequences, singulars are elements of these sequences

Related

LINQ - Left Join And Group By

I have a problem. This is my products class
public int ProductID { get; set; }
public string ProductName { get; set; }
public int CategoryID { get; set; }
public decimal Price { get; set; }
public int CompanyID { get; set; }
public string QuantityPerUnit { get; set;
And this is OrderDetail Class
public int DetailID { get; set; }
public int OrderID { get; set; }
public int ProductID { get; set; }
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public bool Discount { get; set; }
so ı wrote this query in mssql. So, how can I write this query on linq ?
select Products.ProductID, Sum(OrderDetails.Quantity) as 'NumberOfOrdered' from Products
left join OrderDetails on Products.ProductID = OrderDetails.ProductID
group by Products.ProductID
order by Products.ProductID
I Wrote this query but it doesn't work.
from p in _context.Products
join d in _context.OrderDetails on p.ProductsID equals d.ProductsID into t1
from d1 in t1.DefaultIfEmpty()
group new { p, d } by new { p.ProductsID, d.ProductsID } into g
orderby g.Key.ProductsID
select new ProductsOrderDetails
{
ProductsID = g.Key.ProductsID,
QuantityToplam = g.(x=>x.d.Quantity)
}).ToList();
So you have Products, and OrderDetails. Every Product has zero or more OrderDetails, every OrderDetail is the detail of exactly one Product, namely the Product that OrderDetail.ProductId belongs to.
Requirement: From every Product, give me the Id and the sum of the Quantities of all its OrderDetails
Whenever you need the sequence of items, every item with its sub-items, like Schools with their Students, Authors with their Books, Orders with their OrderDetails, consider using one of the overloads of Enumerable.GroupJoin
In this case, I don't want a simple Product with its OrderDetails, I want to compose a special result. For every Product I want the Id and the sum of Quantities of all its OrderDetauls. Therefore I use the Overload with a parameter resultSelector.
var result = dbContext.Products.GroupJoin( // GroupJoin Products
dbContext.OrderDetails, // with Orderdetails
product => product.Id, // From every Product take the Id
orderDetail => orderDetail.ProductId, // From every OrderDetail that the foreign key
// resultSelector: for every Product and all its zero or more OrderDetails
// create one new object
(product, orderDetailsOfThisProduct) => new
{
Id = product.Id,
QuantitiesToPlam = orderDetailsOfThisProduct
.Select(orderDetail => orderDetail.Quantity)
.Sum(),
});
For property QuantitiesToPlam: for every OrderDetail that belongs to this Product: take the value of property Quantity, and Sum them.

LINQ Lazy load or query incorrect

LINQ Query not populating
Model extract is as follows
public class ServiceBulletin
{
[Key]
public int Id { get; set; }
public virtual ICollection<ServiceBulletinProducts> ApplicableProducts { get; set; }
}
public class ServiceBulletinProducts
{
[Key]
public int Id { get; set; }
public int ServiceBulletinId { get; set; }
public virtual Product Product{ get; set; }
}
I'm using the following code at the moment to populate a collection
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts)
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;
var x1 = new List<ServiceBulletin>();
foreach (var item in x)
{
var p = from m1 in _dc.ServiceBulletinsProducts.Include(p2=>p2.Product)
where m1.Product.DeleteStatus == DeleteStatus.Active &&
m1.ServiceBulletinId == item.Id
select m1;
var p99 = p.ToList();
item.ApplicableProducts = p99;
x1.Add(item);
};
So this is intended to have a Parent Child relationship and I’m trying to do a query which populates a collection of ServiceBulletins with a ApplicableProducts item with a fully populated collection of ServiceBulletinProducts for the ServiceBulletin with the values of the Product populated
The collection is populated but the ServiceBulletinProducts are always set to null and I can’t seem to add an Include such as .Include(p => p.ApplicableProducts.Products) to try and populate the product details – which is resulting in me iterating around the collection to populate the items.
Am I missing something to enable the population on the 1st query for the Include statement or do I need to do the query in a different way ?
Figured out the following should do the trick.
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts.Select(p2=>p2.Product))
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;

Combine Parent and Child Lists into a single nested Parent List

I have two lists, a parent list (parents) and a child list (children) with the child list having a parentId.
List<Parent> parents
List<Child> children
I am trying to combine the two lists into a single list of parents with each parent object having a list of children. I'm currently looping through the parent list and populating the Children list within each parent object based on the parentId but I was wondering if there was a faster way to do this using LINQ.
foreach (var parent in parents)
{
parent.Children = children.Where(c=>c.ParentId == parent.Id).ToList();
}
Any suggestions?
You can use a Join, combined with a GroupBy:
var parentChildrenQry =
from parent in parents
join child in children on parent.Id equals child.ParentId
group child by parent;
foreach(var grp in parentChildrenQry) {
grp.Key.Children = grp.ToList();
}
Or both in one statement with GroupJoin:
var parentChildrenQry =
parents.GroupJoin(children, parent.Id, child.ParentId, new { (parent, childGrp) => new { Parent = parent, Children = childGrp.ToList() } );
foreach(var grp in parentChildrenQry) {
grp.Parent.Children = grp.Children;
}
From a performance point of view there is nothing wrong with your foreach.
If your code is readable enough there is no point to make your code linq and fancy.
If your collections are very large, from performance perspective it might be most efficient if you firstly group your children by parent id and sort groups by parent id and get them appended to the sorted parents.
I know it is an old question but I'd like to share my experience
for me I have a lot of records in database so the performance is important I crate it in another way and get the result about 3 times faster. I get all data in one select then put results in my models.
I have restaurant database with menus and dishes tables.
At first these are the classes models that will handle the selected data and are different from database models
public class Menu
{
public Menu()
{
Dishes = new List<Dish>();
}
public long ID { get; set; }
public string Name { get; set; }
public string ImagePath { get; set; }
public List<Dish> Dishes { get; set; }
}
public class Dish
{
public long ID { get; set; }
public string Name { get; set; }
public string PicturePath { get; set; }
public double Price { get; set; }
}
This is the Linq query
var all = (from m in contexts.RestMenus
join d in contexts.ResDishes on m.Id equals d.MenuID
select new
{
Menu = new Menu()
{
ID = m.MenuID,
Name = m.Name,
ImagePath = m.ImageURL
},
Dish = new Dish()
{
ID = d.ItemID,
Name = d.Name,
PicturePath = d.PicturePath,
Price = d.DefaultPrice
}
}).ToList();
and the foreach loop to arrange the data
List<Menu> menus = new List<Menu>();
foreach (var r in all)
{
Menu m = menus.Find(x => x == r.Menu);
if (m == null)
{
menus.Add(r.Menu);
m = r.Menu;
}
m.Dishes.Add(r.Dish);
}

GroupBy loses ThenBy sort order

How do I build an expression that will preserve the ThenBy order?
The Expression below produces the Groups ordered by Bowler.Number but the Matches of each group are not sorted.
public class Match
{
public int Id { get; set; }
public virtual Bowler Bowler { get; set; }
public byte GameNumber { get; set; }
public int Score { get; set; }
...
}
public class Bowler
{
public int Id { get; set; }
public int Number { get; set;}
...
}
var GroupedMatches = db.Matches.OrderBy(m=>m.Bowler.Number).ThenBy(m=>m.GameNumber).GroupBy(m => m.Bowler.Number)
Here is the output I want:
1
game1 295
game2 199
game3 202
game4 178
2
game1 177
...
Current I use two foreach like
foreach (var item in TheGroups){
... do some stuff with the Group
foreach (var x in item.OrderBy(a =>a.Number)) { //<-- can I get rid of this OrderBy?
... do some stuff with the Matches in this group
}
}
No big deal, I just thought LINQ would be able to help me sort the matches in the group when the groups where built, not later when I process them.
I'm not sure what you want the output to be, since it's kind of non-sensical to order a list of groups keyed on bowler number by game number.
Assuming you want an ordered list of bowler numbers, each containing an ordered list of games, something like this might work
var GroupedMatches = db.Matches
.GroupBy(m => m.Bowler.Number)
.OrderBy(g => g.Key)
.Select (g => new
{
BowlerNumber = g.Key,
Matches = g.OrderBy(m => m.GameNumber).ToList()
});
Here's specifically how you get the output you're looking for
foreach(var group in GroupedMatches) {
Console.WriteLine(group.BowlerNumber);
foreach(var match in group.Matches) {
Console.WriteLine("game{0} {1}", match.GameNumber, match.Score);
}
}

linq aggregate

class Category
{
public string Name { get; set; }
public int Count { get; set;}
}
Name Count
AA 2
BB 3
AA 4
I have an IEnumerable<Category>
and would like to get a list of Categories with unique names and the sum of multiple entries
Output
Name Count
AA 6
BB 3
Update
class Category
{
public string Name { get; set; }
public int CountA { get; set;}
public int CountB { get; set;}
public string Phone { get; set;}
}
How would I sum two columns. and the phone column can be the last row or any row
Your updated question isn't entirely clear in terms of the phone number, but I suspect you want something like:
var query = from category in list
group category by category.Name into grouped
select new { Name = grouped.Key,
SumA = grouped.Sum(x => x.CountA),
SumB = grouped.Sum(x => x.CountB),
Phone = grouped.Last().Phone };
Changing grouped.Last() to grouped.First() would be more efficient, by the way.
Evaluating multiple aggregates in this way isn't terribly efficient in general. The Push LINQ project developed by myself and Marc Gravell makes it a lot more efficient at the cost of not being quite as easy to use. You might want to look into it if you need to deal with a lot of data.
var foo = new List<Category>() {
new Category() { Name = "AA", Count = 2},
new Category() { Name = "BB", Count = 3},
new Category() { Name = "AA", Count = 4}
};
var bar = foo.GroupBy(c => c.Name).Select(g => new Category(){ Name = g.Key, Count = g.Sum(c => c.Count) });

Resources