I have a sample to look into Async calls and i need to get a count from the sub query. I know how to write this in a TSQL query but i am bit confused with the iqueryable use.
Here is what i currently have. I am getting the users and then get the count inside a loop. How can i do the loop part in the first query?
public static async Task GetUsers(this List<UserViewModel> users)
{
var db = ApplicationDbContext.Create();
users.AddRange(await (from u in db.Users
select new UserViewModel
{
Id = u.Id,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName
}).OrderBy(o => o.Email).ToListAsync());
if (users.Any())
{
foreach(var user in users)
{
user.SubscriptionsCount = await (from us in db.UserSubscriptions
join s in db.Subscriptions on us.SubscriptionId equals s.Id
where us.UserId.Equals(user.Id)
select us).CountAsync();
}
}
}
Could be handled in one of the following two ways. I have picked #2 for my sample.
1 : with sub query
var singleQuery = from u in db.Users
join sub in (from us in db.UserSubscriptions
join s in db.Subscriptions on us.SubscriptionId equals s.Id
group us by us.UserId into countGroup
select new { Count = countGroup.Count(), UserId = countGroup.Key })
on u.Id equals sub.UserId into sub1
from subR in sub1.DefaultIfEmpty()
select new UserViewModel
{
Id = u.Id,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName,
SubscriptionsCount = subR.Count == null ? 0 : subR.Count
};
var siteUsersSub = await (query).OrderBy(o => o.Email).ToListAsync();
2: Composing from sub queries
var subQuery = from us in db.UserSubscriptions
join s in db.Subscriptions on us.SubscriptionId equals s.Id
group us by us.UserId into countGroup
select new { Count = countGroup.Count(), UserId = countGroup.Key };
var query = from u in db.Users
join sq in subQuery on u.Id equals sq.UserId into sq1
from sqR in sq1.DefaultIfEmpty()
select new UserViewModel()
{
Id = u.Id,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName,
SubscriptionsCount = sqR.Count == null ? 0 : sqR.Count
};
var siteUsers = await(query).OrderBy(o => o.Email).ToListAsync();
Related
I have the following query in SQL which returns 5 rows of data:
SELECT DISTINCT c.Id, c.FirstName, c.LastName, c.PhoneNumber, 'Waiting to be sent'
FROM DistributionGroupMembers dgm
JOIN Contacts c on dgm.ContactId = c.Id
JOIN DistributionGroups dg on dgm.DistributionGroupId = dg.Id
WHERE dg.Id IN (
SELECT DistributionGroupId
FROM DistributionGroupInSms
WHERE SmsId = 40
)
When I try to run the adequate query in C# using LINQ it won't return anything:
int[] groupIDs = await _db.DistributionGroupInSms.Where(dgis => dgis.SmsId == message.Id).Select(g => g.Id).ToArrayAsync();
var recipients = await (from dgm in _db.DistributionGroupMembers
join c in _db.Contacts on dgm.ContactId equals c.Id
join dg in _db.DistributionGroups on dgm.DistributionGroupId equals dg.Id
where groupIDs.Contains(dg.Id)
select new
{
ID = c.Id,
FN = c.FirstName,
LN = c.LastName,
PN = c.PhoneNumber,
SR = "Waiting to be sent"
}).Distinct().ToListAsync();
What am I doing wrong?
Can you simply do a join:
int[] groupIDs = await _db.DistributionGroupInSms.Where(dgis => dgis.SmsId == message.Id).Select(g => g.Id).ToArrayAsync();
var recipients = await (from dgm in _db.DistributionGroupMembers
join c in _db.Contacts on dgm.ContactId equals c.Id
join dg in _db.DistributionGroups on dgm.DistributionGroupId equals dg.Id
join gIds in groupIDs on gIds equals dg.Id
select new
{
ID = c.Id,
FN = c.FirstName,
LN = c.LastName,
PN = c.PhoneNumber,
SR = "Waiting to be sent"
}).Distinct().ToListAsync();
I figured it out, in the select clause by getting the groupIDs I selected Id instead of another field in the table called DistributionGroupId. Thanks everyone for the input
I've this query:
var usersByBranch = (from u in _db.VRT_User
join urb in _db.VRT_UserRoleBranch on u.UserId equals urb.UserId
join r in _db.VRT_Role on urb.RoleId equals r.RoleId
where branches.Contains(urb.BranchId)
select new UserRoleBranchModel
{
UserId = u.UserId,
BranchId = urb.BranchId,
RoleId = urb.RoleId,
RoleName = r.RoleName
});
In this query, for the same userId, the roleId (1-4) and RoleName with the same BranchId are returned separately.
I'd like to flatten the rows, so that a row with the same userId contains all the RoleId and RoleName within the same BranchId.
Your help is greatly appreciated.
Not sure what you mean by contains, but you can't use the same UserRoleBranchModel to hold multiple roles, so an anonymous object will do the job:
var usersByBranch = (from u in _db.VRT_User
join urb in _db.VRT_UserRoleBranch on u.UserId equals urb.UserId
join r in _db.VRT_Role on urb.RoleId equals r.RoleId
where branches.Contains(urb.BranchId)
group r by new { urb.UserId, urb.BranchId } into rg
select new {
UserId = rg.Key.UserId,
BranchId = rg.Key.BranchId,
Roles = rg.Select(r => r)
});
var usersByBranch = (from u in _db.VRT_User
join urb in _db.VRT_UserRoleBranch on u.UserId equals urb.UserId
join r in _db.VRT_Role on urb.RoleId equals r.RoleId
where branches.Contains(urb.BranchId)
group u by u.UserId into g
select new UserRoleBranchModel
{
UserId = g.Key,
BranchId = g.First().BranchId,
RoleId = g.First().RoleId,
RoleName = g.First()RoleName
});
using the northwind DB, i have to make a query to get employeename, amount of orders per employee and average price of those orders
this is what the query looks like in SQL
SELECT TOP 10
a.LastName, a.FirstName, amountOfOrders = COUNT(DISTINCT b.OrderID), AveragePricePerOrder = SUM(c.Quantity*c.UnitPrice) /COUNT(DISTINCT b.OrderID)
FROM Employees a join orders b on (a.EmployeeID = b.EmployeeID)
join [Order Details] c on b.OrderID = c.OrderID
Group BY a.EmployeeID, a.LastName, a.FirstName
ORDER BY amountOfOrders Desc
this runs fine but I have to make this in c# and I am a little stuck
So far, I have got this
var query_rx = (from c in ctx.Employees
join or in ctx.Orders on c.EmployeeID equals or.EmployeeID
join ord in ctx.Order_Details on or.OrderID equals ord.OrderID
group c by new
{
c.EmployeeID,
c.LastName,
c.FirstName,
amount = c.Orders.Count
} into c
orderby c.Key.amount descending
select new
{
c.Key.LastName,
c.Key.FirstName,
amountOfOrders = c.Key.amount
}).Take(10);
"edit" I am having trouble working the average in, tried a lot of things but I can't get it to work
"edit" I have changed the query a bit with help from Dohnal's suggestion.
This looks almost exactly like what i want in terms of columns, except that the field lastname and firstname are blank, even with ToString
var query_rx = (from or in ctx.Order_Details
join ord in ctx.Orders on or.OrderID equals ord.OrderID
group or by new
{
ord.EmployeeID
} into c
orderby c.Select(x => x.OrderID).Distinct().Count() descending
select new
{
Lastname = (from emp in ctx.Employees
where c.Key.EmployeeID == emp.EmployeeID
select emp.LastName),
Firstname = (from emp in ctx.Employees
where c.Key.EmployeeID == emp.EmployeeID
select emp.FirstName),
c.Key.EmployeeID,
AmountOfOrders = c.Select(x => x.OrderID).Distinct().Count(),
AveragePricePerOrder = c.Sum(x => x.Quantity * x.UnitPrice) / c.Select(x => x.OrderID).Distinct().Count()
}).Take(10);
Try this query:
var query = (from emp in ctx.Employers
join order in ctx.Orders on emp.EmployeeID equals order.EmployerID
join orderDet in ctx.Order_Details on order.OrderID equals orderDet.OrderID
group new { emp, order, orderDet }
by new { emp.FirstName, emp.LastName, emp.EmployeeID, order.OrderID }
into orderGroup
let a = new
{
orderGroup.Key.EmployeeID,
orderGroup.Key.FirstName,
orderGroup.Key.LastName,
orderGroup.Key.OrderID,
sum1 = orderGroup.Sum(x => x.orderDet.Quantity * x.orderDet.UnitPrice),
}
group a by new { a.FirstName, a.LastName, a.EmployeeID } into empGroup
let a2 = new
{
empGroup.Key.FirstName,
empGroup.Key.LastName,
sum = empGroup.Sum(x => x.sum1),
count = empGroup.Count()
}
orderby a2.count descending
select new
{
a2.FirstName,
a2.LastName,
amountOfOrders = a2.count,
AveragePricePerOrder = a2.sum / a2.count
}).Take(10);
I have the following code and want to return a limited subset of this query in LINQ. The limited subset will take u.ID as an argument to the function and count the number of records associated with u.ID from another table.
So far, this is what I have.
var res = from u in db.Users
where id == u.WorkGroupID && jobCount(u.ID) > 0
select
new
{
ArtistID = u.ID,
ArtistName = u.FirstName + " " + u.LastName
};
How can I modify this query to limit the number of returned records based on a count value associated with each u.ID?
EDIT:
New Query Below. Last line returns to caller a list from the last LINQ query.
var res = from u in db.Users
where id == u.WorkGroupID
select
new
{
// SELF
ArtistID = u.ID,
ArtistName = u.FirstName + " " + u.LastName
};
var res2 = res.ToList<dynamic>();
var res3 = from row in res2.AsEnumerable()
where jobCount(row.ArtistID) > 0
select new
{
row.ArtistName,
row.ArtistID
};
return res3.ToList<dynamic>();
Use a group join:
from u in db.Users
join o in db.Other on u.ID equals o.UserID into grp
where grp.Any()
select new
{
ArtistID = u.ID,
ArtistName = u.FirstName + " " + u.LastName
};
In my database I have roles and users, I also have user roles to tie the 2 together.
The problem is trying to get all users with their roles (if they have any, which they may not).
I use this query:
return (from ur in db.UserRoles
join r in db.Roles on ur.RoleID equals r.ID
group r by ur.UserProfileID into ugr
join u in db.UserProfiles on ugr.Key equals u.ID
select new UserModel() {
ID = u.ID,
Username = u.UserName,
IsLockedOut = u.IsLockedOut,
LastLoginDate = u.LastLoginDate,
UserRoles = (from r in ugr
select new RoleModel() {
Name = r.Name,
ID = r.ID
}).ToList()
}).ToList();
This works for users who have at least one role, but I also want users who do not have roles.
I'm currently trying to use http://msdn.microsoft.com/en-us/library/bb397895.aspx DefaultIfEmtpy(), but I don't know how and where to place it, meaning however I try my code does not compile.
How do I get all my Users, even if they do not have any UserRoles linked to them?
Get the users first and include their roles from then
return db.UserProfiles
.Include(up => up.UserRoles)
.Select(u => new UserModel() {
ID = u.ID,
Username = u.UserName,
IsLockedOut = u.IsLockedOut,
LastLoginDate = u.LastLoginDate,
UserRoles = u.Roles
.Select(r => new RoleModel() {
Name = r.Name,
ID = r.ID
})
})
.ToList();
Update based on comments
return db.UserProfiles
.Include(up => up.UserRoles)
.Include("UserRoles.Roles") // <-- Added further include
.Select(u => new UserModel() {
ID = u.ID,
Username = u.UserName,
IsLockedOut = u.IsLockedOut,
LastLoginDate = u.LastLoginDate,
// Modified this to use joining table
UserRoles = u.UserRoles
.Select(ur => new RoleModel() {
Name = ur.Role.Name,
ID = ur.RoleID
})
})
.ToList();