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
});
Related
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();
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();
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 a query in entity framework which gets some messages from tables.
var ur = (from m in en.Messages
join mb in en.aspnet_Membership on m.FromUserId equals mb.UserId
join urs in en.UserProfiles on mb.UserId equals urs.UserId
join g in en.Groups on m.ToUserId equals g.GroupId
join ug in en.UserInGroups on g.GroupId equals ug.GroupId
where ug.UserId == userId
select new
{
InboxId = m.MessageId,
FromUser = urs.RaveName.Trim(),
CreatedOn = m.CreatedOn
}
).Concat(
// msg is not deleted
from m in en.Messages
join mb in en.aspnet_Membership on m.FromUserId equals mb.UserId
join urs in en.UserProfiles on mb.UserId equals urs.UserId
where m.ToUserId == userId
select new
{
InboxId = m.MessageId
,
FromUser = urs.RaveName.Trim()
,
CreatedOn = m.CreatedOn
}
);
I have another table which shows whether the message is used:
var msg = (from m in en.MessagesUsed
where m.UserId == userId
select m
);
Now, I need to check: Is there a message in 'ur' that is not in 'msg'? In T-SQL, we can use:
SELECT 1
FROM ur
WHERE NOT EXISTS (SELECT 1 FROM msg WHERE msg.Id = ur.InboxId AND msg.FromUser = ur.FromUser AND msg.CreatedOn = ur.CreatedOn)
to check this. But how to do it in LINQ?
Thanks
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();
}
}