Linq To SQL - Having and Group By - c#

I've this query below working fine. However I want to implement it using Linq.
select u.ID, u.NAME
from Task t
join BuildingUser bu ON bu.ID_BUILDING = t.ID_BUILDING
join [User] u ON u.ID = bu.ID_USER
where t.ID IN (2,9) AND u.ID != t.ID_USER
group by u.id, u.name
having count(bu.ID_BUILDING) = (SELECT COUNT(t2.ID_BUILDING) FROM Task t2 WHERE t2.ID IN (2,9))
I don't know how to Group and use Having clause at the same time.

You can try something like this:
var ids = new[] { 2, 9 };
var results =
from t in db.Tasks
join bu in db.BuildingUsers on t.ID_BUILDING equals bu.ID_BUILDING
group bu by bu.ID_BUILDING into bg
join u in db.Users on bg.Key equals u.ID
where ids.Contains(t.ID) && u.ID != t.ID_USER
group u by new { u.ID, u.NAME } into g
where bg.Count() == db.Tasks.Count(t2 => ids.Contains(t2.ID))
select g.Key;
Or if you have navigation properties set up correctly, you can try this:
var ids = new[] { 2, 9 };
var results =
from t in db.Tasks.Where(x => ids.Contains(x.ID))
from u in t.BuildingUsers.SelectMany(bu => bu.Users)
.Where(x => x.ID != t.ID_USER)
group u by new { u.ID, u.NAME } into g
where t.BuildingUsers.Count() == db.Tasks.Count(x => ids.Contains(x.ID))
select g.Key;

Related

Struggling to convert SQL query to it's LINQ equivalent - Multiple joins, groupings and aggregate functions

I have the following query that gives me expected results in SQL Server Management Studio:
SELECT
u.DisplayName,
up.ColorPreferences,
SUM(rt.Score) AS Points,
COUNT(*) AS Plans,
MAX(pl.Created) AS MaxDate
FROM
[dbo].[Users] u
INNER JOIN
[dbo].[PlanLogs] pl ON u.Id = pl.UserId
INNER JOIN
[dbo].[ResourceTypes] rt ON pl.ResourceTypeId = rt.Id
INNER JOIN
[dbo].[UserProfile] up ON pl.UserId = up.UserId
GROUP BY
u.DisplayName, up.ColorPreferences;
an I have the following working linq query:
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group rt by new { u.DisplayName, up.ColorPreferences} into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(x => x.Score),
Plans = g.Count()
};
As you can see, it is missing MaxDate. I can't get access to MaxDate because g contains properties from rt. I've tried the following and i get "Value does not fall within the expected range"
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group new { rt, pl } by new { u.DisplayName, up.ColorPreferences} into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(x => x.rt.Score),
Plans = g.Count()
MaxDate = g.Max(m => m.pl.Created)
};
How do i add MaxDate to the results?
Thanks
Have you tried accessing the max value from pl.created on your first linq query? why are you grouping by rt and not the whole result? try this instead :
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group u by new { u.DisplayName, up.ColorPreferences} into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(x => x.Score),
Plans = g.Count(),
MaxDate = g.Max(m => m.pl.Created)
};
I solevd this in the end. I needed to pass the specific columns to the group not the whole table:
group new { rt.Score, pl.Created } by..
rather than
group new { rt, pl } by...
Working query:
from u in _context.Users
join pl in _context.PlanLogs on u.Id equals pl.UserId
join rt in _context.ResourceTypes on pl.ResourceTypeId equals rt.ID
join up in _context.UserProfile on pl.UserId equals up.UserId
group new { rt.Score, pl.Created } by new { u.DisplayName, up.ColorPreferences } into g
select new
{
DisplayName = g.Key.DisplayName,
ColorPrefs = g.Key.ColorPreferences,
Points = g.Sum(i => i.Score),
Plans = g.Count(),
MaxCreated = g.Max(i => i.Created).ToString("dd/MM/yyyy HH:mm")
}

How to perform LINQ JOIN with WHERE

I need help to perform JOIN using LINQ with WHERE clause.
The problem is when CaseId in events is null(not all events are case related)
it results in NOT showing event.
Here is my code:
var queryEvents = (from e in db.events
join u in db.users on e.UserID equals u.UserID
join c in db.cases on e.CaseID equals c.CaseID
where e.UserID == Program.loggedUser.UserID || (e.UserGroupID == Program.loggedUser.UserGroupID && c.AccessLvl>0)
select new { User = u.FirstName + " " + u.LastName, e.Name, e.Description, e.StartDate }).OrderByDescending(x => x.StartDate);
gvAppointments.DataSource = queryEvents.ToList();
I found some examples on how to use LINQ LEFT JOIN using INTO but then I have problem with WHERE statement.I honestly don't know where to put it.
Can someone please help me with this?
var queryEvents = (from e in db.events
join u in db.users on e.UserID equals u.UserID
join c in db.cases on e.CaseID equals c.CaseID into cases
from subC in cases.DefaultIfEmpty()
where e.UserID == Program.loggedUser.UserID || (e.UserGroupID == Program.loggedUser.UserGroupID && subC?.AccessLvl ?? 0 > 0)
select new { User = u.FirstName + " " + u.LastName, e.Name, e.Description, e.StartDate }).OrderByDescending(x => x.StartDate);
gvAppointments.DataSource = queryEvents.ToList();
You only must be aware, that subC might be now null, so you have to go for a default value, accessing it's properties.

need to convert sql join query with count into linq and pass it to view

select COUNT([User].UserId)
from [User] join Team on [User].TeamId = Team.TeamId where Team.TeamId =2
Here's what I have so far, but I can't figure out how to implement
var countUser = from u in db.Users
join t in db.Teams
on u.TeamId equals t.TeamId
where (u.TeamId == 11)
select new
{
};
try this
var countUser = (from u in db.Users
join t in db.Teams
on u.TeamId equals t.TeamId
where (u.TeamId == 11)
select new
{
u.UserId
}).Count();

simplifying two queries into one with the same types linq

I have this code:
var commentData = from o in quack.BlogComments
join u in quack.AdminUsers
on o.UserId equals u.AdminUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
};
var commentData2 = from o in quack.BlogComments
join u in quack.RegularUsers
on o.UserId equals u.RegularUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
};
var l = commentData.ToList();
l.AddRange(commentData2);
As you can see above I am doing 2 different queries to the database and then adding them together to generate a single list to be used in the gridview.
What I want is to only use 1 query to the database and will result to two of those table combined.
How can I do it? is it possible with multiple joins?
You should use Concat:
var commentData = (from o in quack.BlogComments
join u in quack.AdminUsers
on o.UserId equals u.AdminUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
}).Concat(from o in quack.BlogComments
join u in quack.RegularUsers
on o.UserId equals u.RegularUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
});
var l = commentData.ToList();

LINQ - multi join with Group by and get average

I'm trying to write this select in LINQ but Im not successful to fix it for long time. I also tried LINQ - join with Group By and get average but it doesn't work in my code. It is obviously that I'm wrong.
SQL:
SELECT name_type, AVG(t.price) as avgPrice FROM type tp
JOIN location l ON l.ID_type = tp.ID
JOIN event e ON e.ID_location = l.ID
JOIN ticket t ON t.ID_event = e.ID
GROUP BY tp.name_type
LINQ:
var q3 = from l in db.location
join tp in db.type on l.ID_type equals tp.ID
join e in db.event on l.ID equals u.ID_location
join t in db.ticket on e.ID equals t.ID_event
group tp by new {Type_name = tp.type_name} into grp
select new
{
Type_name = grp.Key.type_name,
avgPrice = grp.Average( x => x.ticket.price)
};
There are a few problems:
There is an error in the second join—I believe u.ID_location needs to be e.ID_location.
I think you are grouping on the wrong entity, try grouping by t instead of tp.
You don't need the anonymous type in the group by.
Try this:
var results =
from l in db.location
join tp in db.type on l.ID_type equals tp.ID
join e in db.event on l.ID equals e.ID_location
join t in db.ticket on e.ID equals t.ID_event
group t by new tp.type_name into grp
select new
{
Type_name = grp.Key,
avgPrice = grp.Average(x => x.price)
};
If you happen to have navigation properties set up between your entities, this would be a lot easier. It's pretty hard to tell how the entities are supposed to be related, but I'm thinking something like this would work:
// average ticket price per location type
var results =
from t in db.ticket
group t by t.event.location.type.type_name into g
select new
{
Type_name = g.Key,
avgPrice = g.Average(x => x.price)
};
Or in fluent syntax:
var results = db.ticket.GroupBy(t => t.event.location.type.type_name)
.Select(g => new
{
Type_name = g.Key,
avgPrice = g.Average(x => x.price)
});

Categories