Linq How to Group By - c#

I have a query like below. I want to group my values by "RapId"
Result must be come like this:
RaporId 1, List of UserId 15,24,23
RaporId 2, List of UserId 18,45,57
var sorgu = (from ra in Model1
join me in Model2
on ra.RapId equals me.RapId
select new
{
RapId = ra.RapId,
UserId= ra.RaportorId,
})
.GroupBy(x=>x.RapId )
.SelectMany(x => x)
.ToList();
var results = sorgu.GroupBy(p => p.RapId , p => p.UserId,
(key, g) => new { RapId = key, UserId= g.ToList() });
I get an error like this
> Error 39 Cannot convert lambda expression to type
> 'System.Collections.Generic.IEqualityComparer<AnonymousType#1>'
> because it is not a delegate type
What's wrong with this query?

Compiler thinks you are trying to use this overload: But you are passing a lambda expressions instead of IEqualityComparer.I think you just need to remove p => p.UserId :
var results = sorgu.GroupBy(p => p.RapId,
(key, g) => new { RapId = key, UserId= g.ToList() });

Related

C# Linq Lambda Left Outer Join

I need to create a LEFT OUTER JOIN in linq lambda syntax. The SQL I am trying to create a linq equivalent of is:
SELECT DISTINCT
p.PartNum AS PartNum, p.ShortChar01 AS SkuType,
vv.VendorID AS VendorCode,
p.PartDescription AS Description, p.Company AS Company
FROM
Part p WITH (NOLOCK)
INNER JOIN
PartPlant pp ON p.Company = pp.Company AND p.PartNum = pp.PartNum
LEFT OUTER JOIN
Vendor vv On pp.VendorNum = vv.VendorNum
WHERE
p.RefCategory = #refCategory
So as you can see its a fairly simple query joining a few tables. The issue is that it could happen that there is no vendor but we still want the rest of the information hence the left outer join.
My current attempt to recreate this is:
_uow.PartService
.Get()
.Where(p => p.RefCategory.Equals(level2))
.Join(_uow.PartPlantService.Get(),
p => new { p.PartNum, p.Company },
pp => new { pp.PartNum, pp.Company },
(p, pp) => new { Part = p, PartPlant = pp })
.GroupJoin(_uow.VendorService.Get(),
pprc => pprc.PartPlant.VendorNum,
v => v.VendorNum,
(pprc, v) => new { PPRC = pprc, V = v });
I am aware that the select isn't returning the same fields at the moment. I have ignored that for now as I am trying to ensure i am getting the correct values first.
The SQL query returns 41 records with 1 record having a null vendor. The linq query returns 40 records obviously not returning the one with the null vendor. I have tried using GroupJoin() and DefaultIfEmpty() but I cannot get it to work.
Any help would be greatly appreciated.
From the comment and links from user2321864, I managed to get it working as follows:
_uow.PartService.Get().Where(p => p.RefCategory.Equals(level2))
.Join(_uow.PartPlantService.Get(),
p => new { p.PartNum, p.Company },
pp => new { pp.PartNum, pp.Company },
(p, pp) => new { Part = p, PartPlant = pp })
.GroupJoin(_uow.VendorService.Get(),
pprc => pprc.PartPlant.VendorNum,
v => v.VendorNum,
(pprc, v) => new { PPRC = pprc, V = v })
.SelectMany(y => y.V.DefaultIfEmpty(),
(x, y) => new { PPRC = x.PPRC, Vendor = y })
.Select(r => new Level2Parts()
{
CompanyCode = r.PPRC.Part.Company,
Description = r.PPRC.Part.PartDescription,
PartNum = r.PPRC.Part.PartNum,
SkuType = r.PPRC.Part.ShortChar01,
VendorCode = r.Vendor.VendorID
})
.Distinct();

Entity framework complex query to nested C# object

I am having following query here. how do I get similar linq query for this sql.
SELECT *
FROM PublishedLineBar
WHERE PublishedRosterShiftId
IN (SELECT LatestShiftId FROM
( SELECT MAX(PublishedRosterShiftId) as LatestShiftId, DayNumber
FROM PublishedRosterShift
WHERE employeeid = 14454
GROUP BY DayNumber)
as ShiftProjection )
I have used below linq translation, but it is failing somewhere.
var shifts = dbContext.PublishedRosterShifts
.Where(h => h.EmployeeId == EmployeeId);
var inner = shifts
.Select(x => new
{
LatestShiftId = shifts.Max(p => p.PublishedRosterShiftId),
DayNumber = x.DayNumber
})
.GroupBy(s => s.DayNumber)
.Select(g => g.FirstOrDefault());
var q = from f in shifts
select new
{
LatestShiftId = shifts.Max(p => p.PublishedRosterShiftId),
DayNumber = f.DayNumber
};
var query = from l in dbContext.PublishedLineBars
where inner.Select(s => s.LatestShiftId).Contains(l.PublishedRosterShiftId)
select l;
Here is the LINQ equivalent of your subquery used for SQL IN (...) clause (with unnecessary nesting removed):
var inner = dbContext.PublishedRosterShifts
.Where(s => s.EmployeeId == EmployeeId)
.GroupBy(s => s.DayNumber)
.Select(g => g.Max(s => s.PublishedRosterShiftId));
and the query using it:
var query = from l in dbContext.PublishedLineBars
where inner.Contains(l.PublishedRosterShiftId)
select l;
or simply
var query = dbContext.PublishedLineBars
.Where(l => inner.Contains(l.PublishedRosterShiftId));
What you are missing in your attempt is that in SQL SELECT MAX(PublishedRosterShiftId) as LatestShiftId, DayNumber operates on the result of the GROUP BY operator, hence in LINQ the Select should be after GroupBy.

Linq left join with group join

I have set of Users and Visits. (So user do visits)
Visit have User navigation property.
I need to find the users who don't visit.
I can do this by finding the users who visit, finding all of the users then taking the difference.
I was trying to find a solution which is faster.
This is what I have right now:
var users = _db.Users.AsNoTracking().Include(c => c.City).Where(x => x.City.Id == city);
var groupedUsers = _db.Visits.AsNoTracking().Include(c => c.City).Include(a=>a.VisitedBy).Where(x => x.City.Id == city).GroupBy(x => x.VisitedBy).Select(group => new { VisitedBy = group.Key, Count = group.Count() });
var visitingUsers = groupedUsers.Select(user => user.VisitedBy);
var dif = users.Except(visitingUsers);
However I was trying GroupJoin as below:
var results = _db.Users.Include(c => c.City).Where(c => c.City.Id == city).
GroupJoin(_db.Visits.Include(c => c.City).Include(u => u.VisitedBy), u => u.Id, v => v.VisitedBy.Id, (u, v) => new { User = u , Visits = v })
.Select(o=>o.User);
But this gives me all of the Users, I want the users who don't exist in the Visit set.
Any help?
You may be able to avoid the correlated sub-query in the other answer by actually doing the left join with null check. Here's a quick example:
var A = new [] { new Foo { Bar = 1 }, new Foo { Bar = 2 }};
var B = new [] { new Foo { Bar = 2 }};
var C = from x in A
join y in B on x.Bar equals y.Bar into z
from y in z.DefaultIfEmpty()
where y == null
select x;
Check the emitted SQL...
I am not too sure if the city filtering is what you are after however the following should achieve what you desire:
var visitsToCity = _db.Visits.Where(v => v.City.Id == city);
var usersOfCity = _db.Users.Where(u => u.City.Id == city);
var nonVisitingUsers = usersOfCity.Where(u => !visitsToCity.Any(v => v.VisitedBy == u));
The last Where combined with the Any should result in a SQL statement like:
SELECT * FROM Users u WHERE u.CityId = #p0 AND
NOT EXISTS(SELECT 1 FROM Visits v WHERE v.CityId = #p0 AND
v.VisitedById = u.Id)
Where #p0 will be supplied with the value of city.

Converting SQL to Linq with groupby, sum and count

I would like to do a group by and on that a sum and a count. I don't seem to be able to create the solution in linq. How can I convert my query to linq?
SELECT HistoricalBillingProductGroup,
COUNT(*),
BillingPeriod,
SUM(TotalMonthlyChargesOtcAndMrc)
FROM [x].[dbo].[tblReport]
group by BillingPeriod, HistoricalBillingProductGroup
order by BillingPeriod
This is what I got sofar in Linq
var result =
context.Reports.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.FirstOrDefault().HistoricalBillingProductGroup,
BillingPeriod = x.FirstOrDefault().BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
})
.ToString();
The query I get from this is enormous and takes a very long time to load. In SQL its a matter of milliseconds. I hardly doubt this is the solution.
I believe the calls to x.FirstOrDefault() are the source of your problem. Each one of these will result in a very costly inner query inside the SELECT clause of the generated SQL.
Try using the Key property of the IGrouping<T> instead :
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.OrderBy(x => x.Key.BillingPeriod)
.Select(x => new StatisticsReportLine
{
HistoricalBillingProductGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
Or if you prefer query syntax:
var result =
(from r in context.Reports
group r by new { r.BillingPeriod, r.HistoricalBillingProductGroup } into g
orderby g.Key.BillingPeriod
select new StatisticsReportLine
{
HistoricalBillingProductGroup = g.Key.HistoricalBillingProductGroup,
BillingPeriod = g.Key.BillingPeriod,
CountOfRows = g.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
You could try this one:
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
}).ToString();
In the above query you make a group by on two properties, BillingPeriod and HistoricalBillingProductGroup. So in each group that will be created, you will have a key, that will be consisted by these two properties.

Convert to LINQ lambda expression

Simple line:
var x = (from a in arr select a).First();
Console.WriteLine(“First" + x);
How to convert to Lambda expression?
So you want to convert the LINQ query from using query syntax to plain extension method calls?
// var first = (from a in arr select a).First();
var first = arr.First();
// var last = (from a in arr select a).Last();
var last = arr.Last();
// var filtered = (from a in arr where a == 10 select a).First();
// there are a couple of ways to write this:
var filtered1 = arr.Where(a => a == 10)
.First();
var filtered2 = arr.First(a => a == 10); // produces the same result but obtained differently
// now a very complex query (leaving out the type details)
// var query = from a in arr1
// join b in arr2 on a.SomeValue equals b.AnotherValue
// group new { a.Name, Value = a.SomeValue, b.Date }
// by new { a.Name, a.Group } into g
// orderby g.Key.Name, g.Key.Group descending
// select new { g.Key.Name, Count = g.Count() };
var query = arr1.Join(arr2,
a => a.SomeValue,
b => b.AnotherValue,
(a, b) => new { a, b })
.GroupBy(x => new { x.a.Name, x.a.Group },
x => new { x.a.Name, Value = x.a.SomeValue, x.b.Date })
.OrderBy(g => g.Key.Name)
.ThenByDescending(g => g.Key.Group)
.Select(g => new { g.Key.Name, Count = g.Count() });
When you have an expression of the form (from y in x select y), you can almost always write x instead.

Categories

Resources