var EmpRecList = (from ur in db.Users
join ug in db.UserGroups on ur.UserGroupID equals ug.UserGroupID
select new
{
lastName = ur.LastName,
userID = ur.UserID,
firstName = ur.FirstName,
userGroupName = ug.UserGroupNameLang1
}).Where(oh => oh.userGroupName.StartsWith(userCur.UserGroupName))
.OrderBy(x => x.lastName);
I have this code snippet. The problem here is, im getting 2 records with the same user ID. I would like to have a distinct record based on the User ID. Thanks. Tried using distinct method but no success.
You can use GroupBy and than get First record. It will get the first record which is in EmpRecList according to userid after ordering, but it will not ensure the result which you want to get.
Try this
var EmpRecList = (from ur in db.Users
join ug in db.UserGroups on ur.UserGroupID equals ug.UserGroupID
select new
{
lastName = ur.LastName,
userID = ur.UserID,
firstName = ur.FirstName,
userGroupName = ug.UserGroupNameLang1
})
.Where(oh => oh.userGroupName.StartsWith(userCur.UserGroupName))
.GroupBy(g => g.userID).Select(s => s.First()).ToList().OrderBy(x => x.lastName)
The problem here is that you wan't a distinct list of Users BUT your LINQ query is grouping some Users with more than one UserGroups. Performing a distinct on this will not give you a unique list because of different UserGroups.
You need to solve this in your where clause. It needs to be more specific. Instead of your predicate being StartsWith, rather use Equals.
var EmpRecList = (from ur in db.Users
join ug in db.UserGroups on ur.UserGroupID equals ug.UserGroupID
select new
{
lastName = ur.LastName,
userID = ur.UserID,
firstName = ur.FirstName,
userGroupName = ug.UserGroupNameLang1
}).Where(oh => oh.userGroupName.Equals(userCur.UserGroupName))
.OrderBy(x => x.lastName);
It would actually be better to compare the UserGroups by an ID instead of the name.
You can skip the join, so a user with more than one group won't appear twice. I Assumed there is no navigation property to groups, but if there is you can just use ur.UserGroups and you don't need the let definition.
var EmpRecList = (from ur in db.Users
let groups = db.UserGroups.Where(ug => ur.UserGroupID == ug.UserGroupID)
select new
{
lastName = ur.LastName,
userID = ur.UserID,
firstName = ur.FirstName,
userGroupNames = groups.Select(g => g.UserGroupNameLang1)
}).Where(oh => oh.userGroupNames.Any(n => n.StartsWith(userCur.UserGroupName)))
.OrderBy(x => x.lastName);
Related
I have troubles creating this query in LINQ:
USE Northwind
GO
SELECT emp.FirstName, emp.LastName, tr.TerritoryDescription, reg.RegionDescription
FROM Employees emp
INNER JOIN EmployeeTerritories empt ON empt.EmployeeID = emp.EmployeeID
INNER JOIN Territories tr ON tr.TerritoryID = empt.TerritoryID
INNER JOIN Region reg ON reg.RegionID = tr.RegionID
This is my current creation:
var query = await context
.Employees
.Select(x => new
{
x.FirstName,
x.LastName,
TerritoryId = x.EmployeeTerritories. //cannot access properties
})
.ToListAsync();
But i can't easily access EmployeeTerritories properties, since it's not 1:1 relationship. I accept both clues and full solution to this problem.
Edit
So this is what i currently have:
var query = await context
.Employees
.Select(x => new
{
x.FirstName,
x.LastName,
TerritoryDescription = x.EmployeeTerritories
.Select(et => et.Territory.TerritoryDescription)
.ToList(),
RegionDesicription = x.EmployeeTerritories
.Select(et => et.Territory.Region.RegionDescription)
.ToList()
})
.ToListAsync();
Is there a way to optimize it? RegionDescription is now a list that contains one element, but i don't know how to do it the better way.
Try something like this (assuming you have corresponding relations):
var query = await context
.Employees
.Select(x => new
{
x.Employee.FirstName,
x.Employee.LastName,
TerritoryDescription = x.EmployeeTerritories
.Select(et => et.Territory.TerritoryDescription)
.ToList(),
})
.ToListAsync();
UPD
To flatten in your particular case you can use solution posted by #dhrumil shah(it is more generic one) or try something like that, if you have EmployeeTerritories set up in your context :
var query = await context
.EmployeeTerritories
.Select(et => new
{
et.Employee.FirstName,
et.Employee.LastName,
et.Territory.TerritoryDescription,
et.Territory.Region.RegionDescription
})
.ToListAsync();
(from emp in context.Employees
join empt in context.EmployeeTerritories
on emp.EmployeeID equals empt.EmployeeID
join tr in context.EmployeeTerritories
on empt.TerritoryID equals tr.EmployeeID
join reg in context.Region
on reg.RegionID equals tr.RegionID
select new {
emp.FirstName,
emp.LastName,
tr.TerritoryDescription,
reg.RegionDescription
}).ToList();
I'm new to LINQ and Lambda. I want to make query that will get me for every studyYear (1,2,3) students who are studying that year. I've done it without Lambda but I really want to know how to do it with lambda.
var res = from s in db.student
join u in db.EnrolledYear
on s.ID equals u.studentID
join g in db.studyYear
on u.studyYearID equals g.ID
select new
{
Year = g.year,
StudentFName = s.FirstName
StudentLName = s.LastName
};
I checked out other examples with lambda but I didn't really understand .
What I managed is to make inner join between student and enrolled year. Now I don't understand how to finish inner join between enrolled year and study year.
I'm stuck here, I need to make one more join:
var res = db.EnrolledYear.Join(db.student,
u => u.studentID, s => s.ID,
(enroll, student) => new
{
Godina = enroll.year,
FName = student.FirstName
LName = student.LastName
})
.Join(.....?)
Use Include.
Something like:
db.students.Include(x => x.EnrolledYears).ThenInclude(x=>x.StudyYear).Select(new ...)
Every clause in a query will correspond to a lambda call. Just go down to every clause and convert to an appropriate call.
This particular query could be written like so:
db.student
.Join(db.EnrolledYear, s => s.ID, u => u.studentID, (s, u) => new { s, u })
.Join(db.studyYear, x => x.u.studyYearID, g => g.ID, (x, g) => new { x.s, x.u, g })
.Select(x => new
{
Year = x.g.year,
StudentFName = x.s.FirstName,
StudentLName = x.s.LastName,
});
I have two tables Clients and ClientEvaluations, those tables are connected through a foreign key. Each ClientEvaluation has FK to a single Client Entity.
Now i need to query all clients with their last evaluation, no more than one valuation per client. Note that each evaluation has a date.
This code here achieves that in SQL.
SELECT C.Id, MAX(E.EvaluationDate) FROM [dbo].[Clients] as C
JOIN [dbo].[ClientEvaluations] AS E ON E.ClientId = C.Id
GROUP BY C.Id
I have also tried this but the problem with what I'm trying to achieve is that i need to get back from this query the Client entity properties as well.
var lastEvaluations = _db.ClientEvaluations.GroupBy(x => x.ClientId, (x, y) => new { ClientId = x, EvaluationDate = y.Max(z => z.EvaluationDate), }).ToList();
But the query here of course only returns the ClientId and the date, how can i include the whole client entity?
I hope you have configured _dbContext correctly. Then you can use include to do the join operation.
var results = _dbcontext
.Clients
.Include(x => x.ClientEvaluations) //join
.GroupBy(y => y.Id) // group by
.Select(z => new
{
Id = z.Key.Value,
Max = z.Max(x => x.EvaluationDate),
}).ToList();
Or
var results = from c in _dbcontext.Clients
join e in _dbcontext.ClientEvaluations
on c.Id equals e.ClientId
group c by c.Id into cg
select new
{
Id = Id = cg.FirstOrDefault().Id,
Max = cg.Max(x => x.EvaluationDate),
}).ToList();
I am trying to do a join inside a groupjoin using Linq. Here's the scenario - for each lineitem in an order, I want to get some attributes from the variant for that line item(such as variant options and imageid which are stored in variant and product databases). i want to join lineitem, variant and product databases to get these extra information for the lineitem and then groupjoin this lineitem with the order table. i have done this and got the desired result using two queries but I am not sure how many database queries are run. And in the first case(ie in the join, a limit cannot be specified so I just want to make sure that the first iqueryable in the code below is evaluated only when .ToListAsync() is called). Is this the right way to do it? Any help would be greatly appreciated!
public async Task<dynamic> GetOrdersAsync(User user, int pageNumber = 1)
{
var perPage = 10;
var lineItemAndVariant = from l in _context.LineItems
join v in _context.Variants
on l.EcomPlatformVariantId equals v.EcomPlatformVariantId
join p in _context.Products
on v.ProductId equals p.Id
where p.UserId == user.Id
select new
{
l.Id,
l.OrderId,
l.Price,
l.Quantity,
l.EcomPlatformLineItemId,
l.EcomPlatformVariantId,
l.Title,
ImageId = v.ImageId ?? p.ThumbnailId, // for adding image
p.MyVendor,
p.MyVendorId,
v.Option1,
v.Option2,
v.Option3,
p.VariantOption1Label,
p.VariantOption2Label,
p.VariantOption3Label
};
var orders = await _context.Orders
.Where(o => o.UserId == user.Id)
.OrderByDescending(o => o.Id)
.Skip(perPage * (pageNumber - 1)).Take(perPage)
.GroupJoin(lineItemAndVariant, o => o.Id, l => l.OrderId,
(o, lineItems) => new
{
o.Id,
o.EcomPlatformOrderId,
o.CustomerEmail,
o.FirstName,
o.LastName,
o.Address1,
o.Address2,
o.City,
o.Company,
o.Country,
o.Currency,
o.OrderNumber,
o.Phone,
o.Province,
o.TotalPrice,
o.UserId,
o.Zip,
o.CreatedAt,
LineItems = lineItems
})
.AsNoTracking().ToListAsync();
return orders;
}
I'm trying to create a query that groups by a field in the first table, sums a first table field, and includes a single field from a second. I keep getting an error when attempting to refer to a field from the joined table.
Table1: Users
Id
DisplayName
Table2: TimeEntries
WeekEnding
UserId
Hours
Query:
from u in Users
join t in TimeEntries on u.Id equals t.UserId
group t by new {t.WeekEnding, t.UserId } into g
select new {WE = g.Key.WeekEnding, User = g.Key.UserId,
HoursTotal = g.Sum(s => s.Hours), DisplayName = g.First(n => n.DisplayName)}
I've tried many things but "DisplayName" is not a valid field.
Any help on this will be greatly appreciated. Thank you.
Here's a couple options.
from t in TimeEntries
group t by new {t.WeekEnding, t.UserId } into g
let firstT = t.First()
select new
{
WE = g.Key.WeekEnding,
User = g.Key.UserId
HoursTotal = g.Sum(x => x.Hours)
DisplayName = firstT.User.DisplayName
}
from t in TimeEntries
group t by new {t.WeekEnding, t.UserId } into g
let user = (from u in Users where u.UserId == g.Key.UserId select u).Single()
select new
{
WE = g.Key.WeekEnding,
User = g.Key.UserId
HoursTotal = g.Sum(x => x.Hours)
DisplayName = user.DisplayName
}
Enumerable.First(IEnumerable<TSource>, Func<TSource, Boolean>) returns the first element in a sequence that satisfies a specified condition.
But i assume that n.DisplayName is a string not a bool.
Try the other overload instead which simply returns the first element in a sequence:
DisplayName = g.First().DisplayName