How to make left join and group by in linq? - c#

I want to join 3 tables 2 of them inner join one of them left join after that i want to make group by. However, it gives an error. How can I handle that ?
this is code :
var people = from u in db.User.ToList()
join o in db.Offer.ToList() on u.UserId equals o.UserID where o.Statu == "Accepted"
join oz in db.log.ToList() on new { x1 = u.UserId.ToString(), x2 = o.CampaignId.ToString() } equals new { x1 = oz.ID, x2 = oz.CampaignID } into ps
from tbl in ps.DefaultIfEmpty()
group new { u, o, tbl } by new { u.UserId, o.CampaignId, o.Target, tbl.ID} into grp
select new { Username = grp.Key.UserId, CampaignID= grp.Key.CampaignId, Target = grp.Key.Target, id = grp.Key.ID};
Error occurs when i use tbl in group by. But i need to use it. I think some values comes null so it gives an error. How can i handle this ?

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 rewrite sql query to linq

I'm trying to rewrite sql query to linq but can't do it myself.
The most problem for me is to get I,II and III aggregated values.
Sql query:
select o.Name,t.TypeID, SUM(e.I),SUM(e.II),SUM(e.III) from Expenditure e
join Finance f on f.FinanceId = e.FinanceId
join FinanceYear fy on fy.FinanceYearId = f.FinanceYearId and fy.StatusId = 1
join Project p on p.ProjectId = fy.ProjectId
join Organization o on o.OrganizationId = p.OrganizationId
join Type t on t.TypeID = p.TypeID
where fy.Year = 2018
group by o.Name,s.TypeID
and what I have done so far is:
var x = (from e in _db.Expenditures
join f in _db.Finances on e.FinanceId equals f.FinanceId
join fy in _db.FinanceYears on f.FinanceYearId equals fy.FinanceYearId and fy.StatusId = 1 // this does not work, cant join on multiple conditions?
join p in _db.Projects on fy.ProjectId equals p.ProjectId
join o in _db.Organizations on p.OrganizationId equals o.OrganizationId
join s in _db.Types on p.TypeId equals s.TypeId
group new { o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = ?,
II = ?,
III = ?,
}
);
Try something like this:
group new { e, o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = grp.Sum(a => a.e.I),
II = grp.Sum(a => a.e.II),
III = grp.Sum(a => a.e.III),
}
You'll need to adjust the right side of the lambda to navigate to the correct property.
You Need to use the Group by for aggregation methods.
Check the below link for more Knowledge.
How to use aggregate functions in linq with joins?

multiple join on conditions sql to linq

how can i change the sql below to a linq.
select distinct * from dbo.TbleA a
left outer join dbo.TbleB b on a.schid = b.schid
left outer join dbo.TbleC c on b.addrid=c.addrid
and c.userid=a.userid
where b.addrid=1
here is my linq version which is causing error:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid
join c in db.TbleC on new { w = b.addrid, z = a.userid } equals new { w=(int?)c.addrid, z=c.userid}
where (b.addrid == 1)
i am getting error around here:
join c in db.TbleC on new { w = b.addrid, z = a.userid } equals new {
w=(int?)c.addrid, z=c.userid}
i do understand where the problem is i am comparing to two tables in my join.
thanks and the error is:
"the type of one of the expressions in the join clause is incorrect""Type inference failed in the call to join"
b.addrid - int,
a.userid - string,
c.addrid - int?
c.userid - string
We can't really tell what's wrong with your current query in terms of compilation without knowing the types involved, but it wouldn't be equivalent to your original SQL anyway, as you want left outer joins. I suspect you want something more like:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid into bs
from b in bs.DefaultIfEmpty()
join c in db.TbleC on new { w = (int?)b?.addrid, z = a.userid }
equals new { w = c.addrid, z = c.userid } into cs
from c in cs.DefaultIfEmpty()
where (b.addrid == 1)
That's if you can use C# 6 with the null conditional operator, of course. If not, you would at least logically need:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid into bs
from b in bs.DefaultIfEmpty()
join c in db.TbleC on new { w = (b == null ? default(int?) : (int?)b.addrid), z = a.userid }
equals new { w = c.addrid, z = c.userid } into cs
from c in cs.DefaultIfEmpty()
where b == null || b.addrid == 1
I suspect your error is caused by trying to compare anonymous classes within a LinQ statement which are not of the same type. I suggest you change the join to the following:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid
join c in db.TbleC on new { w = (int?)b.addrid, z = a.userid } equals new { w=(int?)c.addrid, z=c.userid}
where (b.addrid == 1)

Count with left outer join in linq to entites

I'm having trouble understanding a left outer join count in Linq to Entities.
My query is:
SELECT Locations.LocationId, Locations.LocationName, LocationPrizes.PrizeId, LocationPrizes.PrizeQuantity, Prizes.PrizeName, ISNULL(COUNT(WonPrizes.WonPrizeId), 0) AS WonPrizes
FROM Locations
INNER JOIN LocationPrizes ON Locations.LocationId = LocationPrizes.LocationId INNER JOIN Prizes ON LocationPrizes.PrizeId = Prizes.PrizeId
LEFT OUTER JOIN WonPrizes ON Locations.LocationId = WonPrizes.LocationId AND Prizes.PrizeId = WonPrizes.PrizeId
GROUP BY Locations.LocationId, Locations.LocationName, LocationPrizes.PrizeId, LocationPrizes.PrizeQuantity, Prizes.PrizeName
My Linq is:
var locationPrizes = from l in context.Locations
select new
{
l.LocationId,
l.LocationName,
Prizes = from o in l.LocationPrizes
select new
{
o.PrizeId,
o.PrizeQuantity,
o.Prize.PrizeJson
}
};
I can't get the count on teh left outer join part working correctly. Any pointers?
If you happen to have an association from LocationPrizes -> WonPrizes you can just do this:
var locationPrizes =
from l in context.Locations
select new
{
l.LocationId,
l.LocationName,
Prizes =
from o in l.LocationPrizes
select new
{
o.PrizeId,
o.PrizeQuantity,
o.Prize.PrizeJson
WonPrizes = o.WonPrizes.Count();
}
};
If not, this will work too (works for me with the minor edits below):
var locationPrizes =
from l in context.Locations
select new
{
l.LocationId,
l.LocationName,
Prizes =
from o in l.LocationPrizes
select new
{
o.PrizeId,
o.PrizeQuantity,
o.Prize.PrizeJson
WonPrizes =
(from w in context.WonPrizes
where w.PrizeId == o.PrizeId
&& w.LocationId == l.LocationId
select w)
.Count()
}
};

Convert special SQL query to Linq

do you know how write this SQL Query to linq ?
SELECT *
FROM
a
INNER JOIN b
ON a.FkSubmissionId = b.Id
RIGHT JOIN c
ON a.FkItemId = c.Id
WHERE
(b.FkUserId = '...' OR b.FkUserId is null)
and
(c.FkTenderId = 2)
I use Linquer and the best I have from the tool is that :
Linq :
from
items in _context.Items
from
si in _context.si
join s in _context.s
on new { fki = si.fki } equals new { fki = s.Id }
into
submissions_join
from
s in submissions_join.DefaultIfEmpty()
...
Result in SQL :
SELECT *
FROM
[Items] AS [t0]
CROSS JOIN [SubmissionsItems] AS [t1]
LEFT OUTER JOIN [Submissions] AS [t2]
ON [t1].[FkSubmissionId] = [t2].[Id]
WHERE
(([t2].[FkUserId] = #p0) OR (([t2].[FkUserId]) IS NULL))
AND
([t0].[FkTenderId] = #p1)
So the final result it not what I get from the query I need...
Thank you for your help !!!
Try this:
var part1 =
from x in a
join y in b on x.FkSubmissionId equals y.Id
where b.FkUserId = "..."
select new {x, y};
var part2 =
from c in z
where c.FkTenderId == 2
join xy in part1
on z.Id equals xy.x.FkItemId
into xys
from xy in xys.DefaultIfEmpty()
select new {xy.x, xy.y, z};
I would reorder your query so you can use a left join instead of a right join
var query = from c in context.C
from a in context.A.Where(x => c.Id == x.FkItemId)
.DefaultIfEmpty()
join b in context.B on a.FkSubmissionId equals b.id
where b.FkUserId == '...' || b.FkUserId == null
where c.FkTenderId == 2
select new {
a,
b,
c
};

Categories