users = (List<UserResponse>)
(from u in _context.Users
join rolePermiss in _context.RolePermissions on u.RoleId equals rolePermiss.RoleId
group new { u, rolePermiss} by u.Id into gr
select new UserResponse()
{
Id = gr.FirstOrDefault().u.Id,
//Permissions = gr.FirstOrDefault().rolePermiss.Select(x => x.Id).ToList()
}).ToList();
try this linq
users = (List<UserResponse>)
(from u in _context.Users
join rolePermiss in _context.RolePermissions on u.RoleId equals rolePermiss.RoleId
group new { u, rolePermiss } by u.Id into gr
select gr.FirstOrDefault() into mr
select new UserResponse()
{
Id = mr.u.Id,
//............
}).ToList();
Related
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();
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);
Right now I have 3 tables: User, Roles, and User_Roles for the many-to-many association. I want to create a search function that takes in a list of RoleIDs and return Users with that role. But if the RoleID list is empty, it should return all Users.
This is what I have so far..
public static List<User> SearchUser(List<int> roleIDs)
{
List<User> userList = new List<User>();
using (var db = new DBContext())
{
var users = (
from u in db.Users
join ur in db.User_Role
on u.UserID equals ur.UserID
join r in roleIDs
on ur.RoleID equals r
select u
).Distinct().ToList();
}
return userList;
}
but I can't figure out a way to conditionally join to User_Role only when roleIDs is not empty.
I also tried this but it didn't work.
var users = (from u in db.Users
from r in roleIDs
join ur in db.User_Role
on u.UserID equals ur.UserID
where roleIDs.Count == 0 || ur.RoleID == r
select u
).Distinct().ToList();
Is it possible to have a conditional join in Entity Framework?
Treat each case separately.
public static List<User> SearchUser(List<int> roleIDs)
{
using (var db = new DBContext())
{
if (roleIDs.Count == 0)
{
return db.Users.ToList();
}
var users = (
from u in db.Users
join ur in db.User_Role
on u.UserID equals ur.UserID
join r in roleIDs
on ur.RoleID equals r
select u
).Distinct().ToList();
return users;
}
}
You can simplify the join as follows if the join table is not mapped as separate entity.
public static List<User> SearchUser(List<int> roleIDs)
{
using (var db = new DBContext())
{
if (roleIDs.Count == 0)
{
return db.Users.ToList();
}
var users = db.Users.Where(u => u.Roles.Any(r => roleIDsContains(r.Id)))
.Distinct().ToList();
return users;
}
}
My biggest was concern keeping the code maintainable as new search criteria is added and to minimize the database calls. I ended up using if statements but didn't load it from the database till the very end. This resulted in one large sent query. I forced the database call by calling .ToList() at the end.
public static List<user> SearchUser(List<int> roleIDs, List<int> hobbyIDs)
{
List<User> Users = new List<User>();
IQueryable<User> tempUsers = null;
using (var db = new DBContent())
{
tempUsers = db.Users;
if (roleIDs.Count > 0)
{
tempUsers = from u in tempUsers
join ur in db.User_Role on u.UserID equals ur.UserID
join r in roleIDs on ur.RoleID equals r
select u;
}
if (hobbyIDs.Count > 0)
{
tempUsers = from u in tempUsers
join uh in db.User_Hobby on u.UserID equals uh.UserID
join h in hobbyIDs on uh.HobbyID equals h
select u;
}
//Go get it from the database
Users = ((ObjectQuery<User>)tempUsers)
.Include("Address").Distinct().ToList();
}
}