Linq query to get get count from multiple tables - c#

I have a query wherein I need to get the count from 2 different tables. Here is a very simple form of the query (my query has more joins and conditions but this is the part I am stuck on):
select (select count(1) from Table1) as One, (select count(1) from Table2) as Two
The following linq queries works but I would like to do the above with a single linq query sent to the SQL Server. This query and many other versions I have tried, result in 2 queries sent to the server:
var query1 = from m in this.Table1 select m;
var query2 = from sr in this.Table2 select sr;
var final = new { One = query1.Count(), Two = query2.Count() };
I also tried this and this also sends 2 queries:
var final = from dummy in new List<int> { 1 }
join one in query1 on 1 equals 1 into ones
join two in query2 on 1 equals 1 into twos
select new { One = ones.Count(), Two = twos.Count()};

You need to make it a single LINQ query that can be translated:
var final = (from m in this.Table1.DefaultIfEmpty()
select new {
One = (from m in this.Table1 select m).Count(),
Two = (from sr in this.Table2 select sr).Count()
}).First();
Note that putting the sub-queries into an IQueryable variable will cause three separate queries to be sent.
Alternatively, since Count() doesn't have a query syntax equivalent, this is a little more compact in lambda syntax:
var final = this.Table1.DefaultIfEmpty().Select(t => new {
One = this.Table1.Count(),
Two = this.Table2.Count()
}).First();

Related

How to write this SQL query as a LINQ statement in .NET Core (C#)?

I'm trying to join three tables together, but I just can't get my LINQ statements to get the data I want to. My SQL query that I want to replicate is like this:
SELECT TOP 5 SUM(Grade) AS 'TotalGrade', COUNT(Restaurants.Name) AS 'NumberOfVisits', Restaurants.Name FROM Lunches
JOIN dbo.LunchRestaurant ON Lunches.LunchId = LunchRestaurant.LunchId
JOIN Restaurants ON Restaurants.RestaurantId = LunchRestaurant.RestaurantId
GROUP BY Restaurants.Name
The LINQ statement I currently have is:
var q = from l in lunchContext.Lunches
join lr in lunchContext.LunchRestaurant on l.LunchId equals lr.LunchId
join r in lunchContext.Restaurants on lr.RestaurantId equals r.RestaurantId
select new { l.Grade, r.RestaurantId};
But with this one, I can't get in my group by statement or the aggregate functions no matter how I try. Do you have any suggestions on what to do? There also doesn't seem to be a way to write raw SQL statements when dealing with several tables, at least not easily done in EF Core if I'm not mistaken. Otherwise that'd be an option too.
I think you're looking for linq grouping. From memory, it would be something like;
var q = from l in lunchContext.Lunches
join lr in lunchContext.LunchRestaurant on l.LunchId equals lr.LunchId
join r in lunchContext.Restaurants on lr.RestaurantId equals r.RestaurantId
group l by lr.RestaurantId into g
select new { Id = g.Key, Grade =g.Sum(x=>x.Grade)};
If you do need to go down the raw SQL route then you can levarage ADO.Net like this
using (var command = lunchContext.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "{Your sql query here}";
context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
// do something with result
}
}

Getting The query contains references do Elements defined in the context of other data Error

I'm facing some problem with DataGridView.
I have two LINQ queries:
var query = from x in db.grupyTowarowes
where x.typ == typMoneta
select new
{
x.grupa
};
var test = from z in dbContext.Pick
join g in db.grupyTowarowes on z.Group equals g.grupa
where z.Number == 1000 && g.typ == typMoneta
select new
{
z.Group
};
And then I am setting DataSource:
dataGridView1.DataSource = test;
Query probably works correctly (don't have any errors with query) but I had some error with binding DataGridView, the error which i got is :
The query contains references do Elements defined in the context of other data.
It's weird because when I set:
dataGridView1.DataSource = query;
Then the output is correct.
Because you are using two data contexts in join (db,dbContext), But Linq does not allow join based on multiple contexts!
So you can fetch the records from one source, iterate it to join with another source;
var list1 = dbContext.Pick.ToList();
var list2 = db.grupyTowarowes.ToList();
var test = from z in list1
join g in list2 on z.ID equals g.Id
select new
{
z.A
};
Or materialize your query by using AsEnumerable will fix your issue
:
var test = from z in dbContext.Pick.AsEnumerable()
join g in db.grupyTowarowes.AsEnumerable() on z.Group equals g.grupa
where z.Number == 1000 && g.typ == typMoneta
select new
{
z.Group
};
With AsEnumerable after data is loaded, any further operation is performed using Linq to Objects, on the data already in memory.
Use ToList()
dataGridView1.DataSource = test.ToList();
Problem with your second query is, you are trying to JOIN from two different DB's as pointed below which is not possible. Better, you run each query separately and perform a LINQ - Object join to get the result
from z in dbContext.Pick
join g in db.grupyTowarowes
Try this
dataGridView1.DataSource = new BindingList<String>(test.ToList());

How to convert Group By SQL to LINQ?

I have the following SQL statement I'm trying to convert to Entity Framework.
SELECT S_NUMBER,A_NUMBER,FIRST_NAME,LAST_NAME
FROM EMPLOYEE WHERE S_NUMBER IN (
SELECT S_NUMBER
FROM EMPLOYEE
WHERE CO='ABC'
GROUP BY S_NUMBER
HAVING COUNT(*) > 1)
I've done some searching on using Group By in LINQ as well as sub-queries. I'm using LinqPad with a "C# Statement" and I came up with the following which based on some examples I found looks like it should work. However, I'm getting errors when trying to assign esn.S_NUMBER to sNumber in the anonymous object. The message says 'IGrouping' does not contain a definition for 'S_NUMBER'.
var result = from e in EMPLOYEE
where e.CO=="ABC"
group e by e.S_NUMBER into esn
select new
{
sNumber = esn.S_NUMBER
};
result.Dump();
I was under the impression that all the records would basically get put into a temp table called esn and I could be able to call the temptable.column name to assign it to my object that I will eventually return as a list.
You want to use Key instead of S_NUMBER. When grouping, the results get put into a IEnumerable<IGrouping>>. The grouping has a Key property which holds the key for that group, which in this case it's your S_NUMBER.
select new
{
sNumber = esn.Key
};
The following query should be a translation of the original SQL query. Instead of using a subquery, we're grouping and doing another from...in to "flatten" the sequence, and also checking that each grouping has a count > 1 like the original query.
var result = from e in EMPLOYEE
where e.CO=="ABC"
group e by e.S_NUMBER into esn
from e2 in esn
where esn.Count() > 1
select new
{
e.S_NUMBER,
e.A_NUMBER,
e.FIRST_NAME,
e.LAST_NAME
};
Since you're using the results of one query to filter another we can do a fairly direct transliteration of the query like so:
var result =
from e in EMPLOYEE
join f in (
from fe in EMPLOYEE
where fe.CO == 'ABC'
group null by S_NUMBER into grp
where grp.Count() > 1
select grp.Key
)
on e.S_NUMBER equals f
select new { e.S_NUMBER, e.A_NUMBER, e.FIRST_NAME, e.LAST_NAME };
Not only does this look a lot more like the original query but it should perform a bit faster (on MS SQL at least, can't speak for others) than the other form that might be simpler in LINQ but is much more complex when converted to SQL... four selects and a cross join, in my test version, vs two selects and an inner join for this one.
Of course if you prefer you can pull the inner query out as a separate IQueryable for clarity:
var filter =
from e in EMPLOYEE
where e.CO == 'ABC'
group null by S_NUMBER into grp
where grp.Count() > 1
select grp.Key;
var result =
from e in EMPLOYEE
join f in filter
on e.S_NUMBER equals f
select new { e.S_NUMBER, e.A_NUMBER, e.FIRST_NAME, e.LAST_NAME };

Selecting the whole data after joining in linq

When I need to join some tables using linq, and when those tables consist of a lot of fields, it takes a lot of work to get all the data that I need. For instance:
var result = from i in Person
join y in Works
on i.PID euqals y.PID
join z in Groups
on y.GID on z.GID
select new {Name = i.Name, Work = y.work, WG = z.GroupName};
How can make the query return all the tables ?
I guess what you need is simply this :
var Query = from x in Table_1
join y in Table_2
on x.id equals y.id
where x.Country.Equals("X Country")
select new {x,y};

Linq to SQL: Sum with multiple columns select

I want to convert the following SQL code into linq to sql but can't seem to find a way
select holder_name,agent_code,sum(total)
from agent_commission
group by agent_code
Can anyone help me? Am kinda stuck with this for quite a while.
Thanks in advance
UPDATE:
I tried the following
var query = (from p in context.Agent_Commissions
group p by new
{
p.agent_code
}
into s
select new
{
amount = s.Sum(q => q.total),
}
);
How do I select the other two columns? What am I missing?
In fact your SQL query works only when the corresponding relationship between holder_name and agent_code is 1-1, otherwise the Group by agent_code won't work. So your linq query should be like this:
var query = from p in context.Agent_Commissions
group p by p.agent_code into s
select new {
holder_name = s.FirstOrDefault().holder_name,
agent_code = s.Key,
amount = s.Sum(q => q.total)
};
Here is your linq query
from a in ctx.agent_code
group a by a.holder_name, a.code into totals
select { holder_name = a.holder_name,
code = a.code,
total = totals.Sum(t=>t.total)}
Given that you have linq2sql context in ctx variable and it has your table in it.

Categories