Linq group by and select sum - c#

I currently have 2 lists, one is records, one is for cards. I'm trying to join these two lists on a shared GUID, then group by the name of the card to find the total quantity of cards with that name. I'm just not sure how to get this group by statement to work, does anyone have any ideas?
var values = (from r in records
join c in cards
on r.CardGUID equals c.GUID
orderby c.Name ascending
select new
{
Name = c.Name,
Quantity = r.Quantity
})
.GroupBy(e => new { e.Name });

If you want to calculate the sum of quantities within each group you would add something like this after your groupBy:
.Select(group => new {group.Key, group.Sum(g => g.Quantity)});
I.e. for each group you create a new object, with the key/name and the sum of quantities for that group.

Related

Join Error | Unable to create a constant value of type only primitive

Very new with LINQ here.
I have the following data in my table (TableA):
ID Name SubmissionNo
1 Jim A-1
2 Andy A-2
3 Rick A-2
4 Mary A-3
5 Zim A-4
6 Loren A-1
I then need to create a query which will allow me to get from that table, those records which have duplicate submission numbers.
Here's my solution so far (Context is the database context):
var duplicates = (from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
select new { count = grp.Count(), submissionNo = grp.Key})
.Where(x => x.count > 1)
.OrderBy(y => y.submissionNo).ToList();
The variable duplicates then contains the record:
count submissionNo
2 A-1
2 A-2
I then write the main query which will allow me to get all the records from TableA which has duplicate submissionNo
var myList = (from tbl in Context.TableA.AsNoTracking()
join dup in duplicates on tbl.SubmissionNo equals dup.submissionNo
select new
{
ID = tbl.ID,
Name = tbl.Name,
SubmissionNo = tbl.SubmissionNo
})
.ToList();
I am then getting an error for the myList query with
Unable to create a constant value of type 'Anonymous Type'. Only primitive types or enumeration types are supported in this context.
I think there must be a better way to do this as from the TableA above, I practically want the following results:
ID Name SubmissionNo
1 Jim A-1
2 Andy A-2
3 Rick A-2
6 Loren A-1
Your first query, slightly modified, has all information you need:
var myList = from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
where grp.Count() > 1
from item in grp
select new
{
count = grp.Count(),
submissionNo = grp.Key,
item.Name,
);
The pattern group into grp - from item in grp is a commonly used query pattern to group items and then flatten the group again, while keeping in touch with the group data (like Count() and Key).
Now you don't need the join anymore and the exception doesn't occur. By the way, the exception tells you that EF can only handle joins with collections of primitive types (int etc.), because it has to translate the whole expression into SQL. There's simply no translation for rich objects like TableA.
By the way, the query can be improved by removing the repeated Count():
var myList = from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
let count = grp.Count()
where count > 1
from item in grp
select new
{
count = count,
submissionNo = grp.Key,
item.Name,
);
This will generate a more efficient SQL statement containing one COUNT instead of two.
Since Entity Framework does not support joining in-memory collections of objects with database collections, a common workaround for this is to filter using Contains.
First, you need to get the IDs to filter on:
var duplicates = (from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
select new { count = grp.Count(), submissionNo = grp.Key})
.Where(x => x.count > 1)
.OrderBy(y => y.submissionNo)
.ToList();
var duplicateIds = duplicates.Select(x => x.submissionNo).ToList();
And then change your query to perform a WHERE...IN instead of a JOIN:
var myList = (from tbl in Context.TableA.AsNoTracking()
where duplicateIDs.Contains(tbl.SubmissionNo)
select new
{
ID = tbl.ID,
Name = tbl.Name,
SubmissionNo = tbl.SubmissionNo
})
.ToList();

select rows whose sum greater than 0 using Linq

I need to do, for example: Select customers whose total Sum of Amount is greater than 0. I tried below code and with reference to this result trying fetch data. but not getting Proper result.
var query = (from a in saleList
group a by a.Cust_Ledger_Entry_No into groups
select groups.Sum( s => s.Amount) > 0).ToList();
I did above query.Now I need data which satisfying above condition.Please help me.
You need a Where
var query = from a in saleList
group a by a.Cust_Ledger_Entry_No into g
where g.Sum( s => s.Amount) > 0
select new { Cust_Ledger_Entry_No = g.Key, SumAmount = g.Sum( s => s.Amount) };
I need result like, customers whose sum of amount greater than 0
with all columns
If a is the customer and you need to select all you can use this query:
var query = from a in saleList
group a by a.Cust_Ledger_Entry_No into g
where g.Sum( s => s.Amount) > 0
from customer in g // flatten each group
select customer;

Group By and Sum In LINQ query with Join

I have a query in C# and i need to group by this query for c.Same_invoice and sum the column price in the row grouped.
I know how to do group by and sum but i don't know the solution for my case, with a join and a large amount of data.
The actual code is:
var query = from c in snd.external_invoices.OrderByDescending(x => x.date)
join o in snd.invoices on c.idexternal_invoices equals o.id_external_invoice
select new{
c.idexternal_invoices,
c.businessname,
o.number,
c.message,
c.price,
c.date,
c.iduser
};
Thank to all
You can use something like:
var query = from c in snd.external_invoices.OrderByDescending(x => x.date)
join o in snd.invoices on c.idexternal_invoices equals o.id_external_invoice into grouped
select new{
Invoice =grouped.key, Price = grouped.Sum(x => x.Price)};

Linq, combining multiple records into comma separated string, grouped by distinct value

I'm trying to do a groupby distinct, then build a csv string:
[FROM] is a one-to-many join:
var allCustomerRoles = (from cr in Customers
join r in CustomerRoles
on cr.Role_ID equals r.Role_ID
select new { cr.Customer_No_, r.Role_ID });
So the question is, can you please show me how to write the LINQ query to arrive at the [TO] structure, where Customer_No_ is distinct and it's Role_ID values are concatenated into a CSV string.
Thank you #reda-mattar, your link led me to the solution, here's what I was looking for:
var allCustomerRoles = (from cr in Customers
join r in Roles
on cr.Role_ID equals r.Role_ID
group r.Role_ID by cr.Customer_No_ into g
select new { Customer_No_ = g.Key, Role_ID = string.Join(",", g.ToArray()) });

How to use linq-to-sql group by to list duplicated records?

Suppose I have two tables: Category and Product. I want use linq-to-sql to select all categories (with products) that have duplicated products.
My query goes like this:
from p in db.Products
group p by p.CategoryId into c
select new
{
categoryId = c.Key,
products = from PbyC in c
group PbyC by PbyC.Name into dupl
where dupl.Count() > 1
select dupl;
}
It works but LINQPad lists empty Categories (without any duplicated Product). How to modify the query?
It would be great to have Category name display somehow instead of Id.
EDIT: I have relationship between tables.
db.Products.GroupBy(p => new { p.Name, p.CategoryId })
.Select(g => new { g.Key.CategoryId, Count = g.Count })
.Where(ng => ng.Count > 1)
.Select(ng => ng.CategoryId);
That'll select the ids of the categories with more than one Product of the same name, and is assuming you don't have any relationships set up between the objects so you'll need to join the results to the Categories table to get detailed info.
If you do have a relationship set up then you can always change the CategoryId to Category (or whatever the related object is named) and just select Category.Name in the last Select.

Categories