Get foreign key table with a single query using LINQ - c#

I have the following two tables
Groups
- Id
- Name
Members
- Id
- GroupId
- Name
I want to display a list of Groups with their member count. I can get all the groups and then use a foreach statement to count the number of members. But this is very inefficient.
Is there a way to write a LINQ query that will return the member count in a single query?

You can do it with a simple linq-to-entities query. You can either project it to an anonymous type or you can create your own class to store the information.
var query = from g in context.Groups
join m in context.Members on g.Id equals m.GroupId into members
select new
{
Group = g,
MemberCount = members.Count(),
};

If there are foreign key relationships, wouldn't this work?
var q = context.Groups.Select(x => new { Group = x.Name, Count = x.Members.Count() } );

Related

Why do I need distinct with this LINQ query but not with SQL

Im getting a list of codes from a table and their respective count. I dont need to use distinct in SQL, but if I do not add this in the LINQ query, I get many dupe rows.
So, why would I need the distinct call on the LINQ query?
SQL
SELECT COUNT(*) AS ServiceCodeCnt, d.ServiceCode
FROM dbo.BackOrderItem d
GROUP BY d.ServiceCode, d.Model
HAVING d.Model ='UUTTIISJWW'
LINQ (via LINQpad)
void Main()
{
var retval = (from a in BackOrderItems where a.Model == "UUTTIISJWW"
group a by new {a.ServiceCode, a.Model} into grp1
from b in grp1
select new {Code = b.ServiceCode, Count = grp1.Count( ) }).ToList().Distinct();
retval.Dump();
}
The statement ...
from b in grp1
... flattens the grouping. So you select all individual rows in each group, each with the count of its group.
Just remove this statement, so it becomes:
var retval = (from a in BackOrderItems where a.Model == "UUTTIISJWW"
group a by a.ServiceCode into grp1
select new
{
Code = grp1.Key,
Count = grp1.Count()
})
.ToList();
Note that I also removed Model from the grouping. It's not necessary, because you only filter out one Model.

IGrouping does not contain a definition for

I've been looking at other threads here to learn how to do a GroupBy in linq. I am following the EXACT syntax that has worked for others, but, it's not working.
Here's the query:
var results = from p in pending
group p by p.ContactID into g
let amount = g.Sum(s => s.Amount)
select new PaymentItemModel
{
ContactID = g.ContactID, // <--- Error here
Amount = amount
};
pending is a List<T> that contains, among other columns, ContactID and Amount, but those are the only two I care about for this query.
The trouble is, inside the the select new, the g. won't give me any of the columns inside the original list, pending. And when I try, I get:
IGrouping <int, LeadPurchases> does not contain a definition for ContactID, and no extension method blah blah blah...
This is the SQL I am trying to emulate:
SELECT
lp.PurchasedFromContactID,
SUM (lp.Amount)
FROM
LeadPurchases lp
GROUP BY
lp.PurchasedFromContactID
You are grouping on the basis of ContactID, so it should be the Key for the result, So you have to use g.Key instead of g.ContactID; Which means the query should be like the following:
from p in pending
group p by p.ContactID into g
let amount = g.Sum(s => s.Amount)
select new PaymentItemModel
{
ContactID = g.Key,
Amount = amount
};
updates :
If you want to perform grouping based on more than one column then the GroupBy clause will be like this:
group p by new
{
p.ContactID,
p.Field2,
p.Field3
}into g
select new PaymentItemModel()
{
ContactID = g.Key.ContactID,
anotherField = g.Key.Field2,
nextField = g.Key.Field3
};

Convert SQL statement to Linq-to-SQL with 2 columns with a count(*) not working

I have a SQL statement that I need to convert to Linq-to-SQL.
The SQL statement that works is
Select
Comment, count(*) as counted
from
[ESO].[ESO].[DOCCCOIssues]
group by
comment
Linq I have an issue with
var issueModel = new IssuesModel();
var query = (from c in DOCCCOIssues//.IssuesModels
//group c by c.Comment into g
select new
{
c.Comment,
//Count = g.Count()
});
I know how to specify a bunch of fields
I did comment out an example i saw of someone doing a group by with a count - not sure how to get this to work
I have seen the linq queries of ONLY getting select c).Count(), and that is not want I want
Once you have done the group by you have a list where each entry is iself an IEnumerable of the things in each group and has a Key property (the thing you grouped on, in this case Comment). See Group Elements in a Sequence on MSDN.
So in your result, you just need to return the Key as the Comment and then the Count() in that grouping, as you already tried:
var query = (from c in DOCCCOIssues//.IssuesModels
group c by c.Comment into g
select new
{
Comment = g.Key,
Count = g.Count()
});
Working .NetFiddle

Select list with linq

I have 2 tables in a database, and one class in C# (Letter).
Tables: tblUser(Id, Name), tblLetter(Id, UserId, Title)
Letter: (Id, Title, UserName)
I want select data with linq, and use this code:
List<Letter> lst = new List<Letter>();
lst = (from l in l.tblLetter.ToList()
select new {l.Id, l.Title, UserName = l.tblUser.Name}
).ToList();
and:
List<Letter> lst = new List<Letter>
(from l in l.tblLetter.ToList()
select new {l.Id, l.Title, UserName = l.tblUser.Name});
but get this error:
Cannot implicitly convert type...
As #SnowYetis comments, you are actually selecting an instance of a new, anonymous type in your code. That's what the syntax new { ... } does. Notice that there's no type name after the new directive.
If your Letter type has the properties Id, Title, UserName then all you need to do is change new { ... } to new Letter { ... }.
If not, then we probably need more information than you're giving us—for example, the definition of the Letter type.
There are a few issues in your code:
l.tblLetter.ToList() returns all records from your table. You typically don't call ToList() until the end of your query, to get just the data you need and no more.
You want to do a join between the two tables to get the matching user name.
If you want to return a collection of Letter, you can create instances of that in your select statement instead of creating an anonymous type.
Try this:
var lst = (from l in l.tblLetter
join u in tblUser on l.UserId equals u.Id
select new Letter
{
Id = l.Id,
Title = l.Title,
UserName = u.Name
}).ToList();

How to cast a Linq Dynamic Query result as a custom class?

Normally, I do this:
var a = from p in db.Products
where p.ProductType == "Tee Shirt"
group p by p.ProductColor into g
select new Category {
PropertyType = g.Key,
Count = g.Count() }
But I have code like this:
var a = Products
.Where("ProductType == #0", "Tee Shirt")
.GroupBy("ProductColor", "it")
.Select("new ( Key, it.Count() as int )");
What syntax could I alter to produce identical results, i.e., how do I do a projection of Category from the second Linq statement?
I know in both that g and it are the same and represent the entire table record, and that I am pulling the entire record in just to do a count. I need to fix that too. Edit: Marcelo Cantos pointed out that Linq is smart enough to not pull unnecessary data. Thanks!
Why would you have to do it at all? Since you still have all of the information after the GroupBy call, you can easily do this:
var a = Products
.Where("ProductType == #0", "Tee Shirt")
.GroupBy("ProductColor", "it")
.Select(c => new Category {
PropertyType = g.Key, Count = g.Count()
});
The type of Products should still flow through and be accessible and the regular groupings/filtering shouldn't mutate the type that is flowing through the extension methods.

Categories

Resources