Can't select properties after group by in linq query - c#

I have two tables, Organization and ApplicationUser. The relationship between them is One to Many. That means one Organization can have multiple Users. Now I need to write a query to show some organization properties along with the total users for each organization. I am trying to write the query. But after GroupBy function whenever I try to fetch the Property nothing comes. Here is the query:
var lists = await (from org in _dbContext.Organizations.AsNoTracking()
join dept in _dbContext.Departments.AsNoTracking() on org.Id equals dept.OrganizationId into orgDeptTemp
from orgDept in orgDeptTemp.DefaultIfEmpty()
join user in _dbContext.ApplicationUsers.AsNoTracking() on org.Id equals user.OrganizationId into orgUserTemp
from orgUser in orgUserTemp.DefaultIfEmpty()
group org by org.Id into orgGroupTemp
select new OrganizationDto
{
OrganizationId = orgGroupTemp.Key,
OrganizationName = orgGroupTemp.Key.......,
TotalUsers = How to get the total user
})
.ToListAsync();

In SQL the only available columns after a GROUP BY are the group key and aggregated columns.
You need to add them into the group by line. So for example, group by org id and name

assuming your model is set up correctly use navigation properties
var query = from org in _dbContext.Organizations
where org.Departments.Any(d => d.Whatever)
select new OrganizationDto
{
OrganizationId = org.Id,
OrganizationName = org.Name,
TotalUsers = org.Users.Count(),
};
var list = await query.AsNoTracking().ToListAsync();

Related

Select with JOIN, Group BY and SUM in related 1:n tables (2nd level of child table) with LINQ / EF-Core

I have these tables which have 1:n and then 1:n relationship with each other:
How can I sum up the amount of Expenses for one specific household?
This is my SQL for that:
SELECT households.Id as HouseholdId,
households.Name HouseholdName,
SUM(expenses.Amount) as SumExpenses
FROM [Households] households
INNER JOIN Accounts accounts
ON households.Id = accounts.HouseholdId
INNER JOIn Expenses expenses
ON expenses.AccountId = accounts.Id
WHERE households.Id = '2AFAB095-39D6-4637-1FC1-08DAC249FA0A'
GROUP BY households.Id, households.Name;
This is what I have done so far:
var results = await (
from household in Context.Households
join account in Context.Accounts
on household.Id equals account.HouseholdId
join expense in Context.Expenses
on account.Id equals expense.AccountId
group new { household }
by new { household.Id, household.Name, AccountName = account.Name, Amount = expense.Amount}
into g
select new
{
HouseholdId = g.Key.Id,
HouseholdName = g.Key.Name,
AccountName = g.Key.AccountName,
//What to do here to get the sum?
}).ToListAsync();
LNQ grouping has the same behaviour as in the SQL. If you add additional grouping keys - you will fail. Important part is what to group.
Also I have removed other artifacts which are not present in your original SQL. You have test that adding additional grouping keys will not change result.
var householdId = ...;
var query =
from household in Context.Households
join account in Context.Accounts
on household.Id equals account.HouseholdId
join expense in Context.Expenses
on account.Id equals expense.AccountId
where household.Id == householdId
group expense
by new { household.Id, household.Name }
into g
select new
{
HouseholdId = g.Key.Id,
HouseholdName = g.Key.Name,
SumExpenses = g.Sum(x => x.Amount)
};

Get TOP5 records from each status using Linq C#

I have a VacancyApply table and that table consist of Status Id's,So i need Top5 data from each Status.I want to get top 5 records of each status.Status is int like 1,2,3
My Query
var result = (from ui in _context.VacancyApply
join s in _context.UserProfile on ui.UserId equals s.UserId
join x in _context.Vacancy on ui.VacancyId equals x.VacancyId
join st in _context.Status on ui.StatusId equals st.StatusId
where ui.UserId == userId && ui.IsActive == true
orderby ui.StatusId
select new VacancyApply
{
VacancyApplyId = ui.VacancyApplyId,
VacancyId = ui.VacancyId,
UserId = ui.UserId,
StatusId = ui.StatusId,
VacancyName = x.VacancyName,
VacancyStack = x.VacancyStack,
VacancyEndDate = x.VacancyEndDate,
StatusName = st.StatusName,
UserName = s.FirstName
}).ToList();
Now what I can see from the output is that it contains One VacancyId and One VendorId.
I have a feeling that you have Many to Many relationships between Vacancy and Status tables.
But nevertheless, the answer is very simple: you need to use LINQ Take extension method (maybe it will be good to make it follow after the OrderBy because just taking the last items doesn't make sense without some logic):
var output = (logic to join, filter, etc.).OrderBy(lambda).Take(N); // N is the number of
// items you want to select
Now if you want Generally to take the last items from Vacancy and only after join it with Status do this:
var output = Vacancy.OrderBy(lambda).Take(N).(now join, filter, etc. with other tables);
However, if you want to Group all similar Statuses in conjunction with Vacancies and only after taking the Top items, use GroupBy:
var output = (logic to join, filter, etc.).GroupBy(st => st.StausId).
.Select(group => group.OrderBy(lambda).Take(N));

Select data from 3 tables with Linq to SQL

I have 3 tables. Orders, OrderItems and OrderItemServices. Each order can contain multiple OrderItems and each OrderItem can contain multiple OrderItemServices.
I want to get a list of data of all orders from these tables in Linq. I could write a join but how do I make an anonymous data type to in select clasue which can give me Order list in this hierarchy?
If I use navigation properties and then select OrderItemServices in side select clause shown below it would fire individual select query for each OrderItemService which I want to avoid.
from order in Orders
select new
{
ActiveOrders = order,
ActiveOrderItems =order.OrderItems,
ActiveServices = order.OrderItems.Select(o => o.OrderItemServices)
}
Is it possible to group each order with a structure of multiple items inside it and multiple services inside items?
Refer msdn to start on LINQ To SQL
To get data from three tables you can get idea from the following simple example
var data = (from product in context.Products
from department in context.Departments
from category in context.Categories
where product.DeptId == department.DeptId
&& product.CatId == category.CatId
select new
{
product.Code,
product.Name,
department.Name,
category.Name
}).Distinct.ToList();
You have to set up your context to use eager loading:
var context = new MyDataContext();
var options = new DataLoadOptions();
options.LoadWith<Orders>(x => x.OrderItems);
options.LoadWith<OrderItems>(x => x.OrderItemServices);
context.LoadOptions = options;
var query = from order in context.Orders // ... etc
Then sub items will be included in initial query result and won't cause additional requests to the database. This will use JOIN internally to retrieve all the data in one go. You can check generated SQL using SQL Server Profiler.
http://blog.stevensanderson.com/2007/12/02/linq-to-sql-lazy-and-eager-loading-hiccups/

Linq one-to-many Union

I'm developing a MVC web application using asp.net C# and VS2012 Express.
I have a table (Organizations) with one-to-many relationships with two other tables (Comments and Proposals). All three tables contain an OrganizationID field to maintain the relationships. All three tables have an AddedBy string field.
I want to find all Organizations where either the Organization.AddedBy="Joe" or Comments.AddedBy="Joe" or Proposals.AddedBy="Joe".
These queries do a join, but I'm looking for a union that contains only the Organizations' fields.
// Find organizations created by this person.
IQueryable<Organization> org = from m in context.Organizations
where m.AddedBy.Equals("Joe")
select m;
// Find Comments created by this person.
IQueryable<Comment> comment = from m in context.Comments
where m.AddedBy.Equals("Joe")
select m;
// Join our two queries.
IQueryable<Comment> organizations = (from item in org
join c in comment on item.OrganizationID equals c.OrganizationID
select item).Distinct();
// Find Proposals created by this person.
IQueryable<Proposal> proposal = from m in context.Proposals
where m.AddedBy.Equals("Joe")
select m;
// Join our two queries.
organizations = (from item in organizations
join c in proposal on item.OrganizationID equals c.OrganizationID
select item).Distinct();
Thanks for your help.
If you are using Entity Framework you can do either:
var orgs = context.Organizations
.Where(O => O.AddedBy.Equals("Joe") ||
O.Comments.Any(C => C.AddedBy.Equals("joe")) ||
O.Proposals.Any(P => P.AddedBy.Equals("joe")));
As EF maintaining the parent-child relationship with navigation properties.
Hope this will help !!
So you're looking for three different sets, all combined. Just query each of those three things and then combine them using Union:
string user = "Joe";
var addedOrganizations = context.Organizations.Where(org => org.AddedBy == user);
var orgsWithUsersComments = from org in context.Organizations
join c in context.Comments
on org.OrganizationID equals c.OrganizationID
where c.AddedBy == user
select org;
var orgsWithUsersProposals = from org in context.Organizations
join p in context.Proposals
where p.AddedBy == user
select org;
var combinedResults = addedOrganizations.Union(orgsWithUsersComments)
.Union(orgsWithUsersProposals);

How to write a LINQ query to select from a collection with given set of matching IDs

I'm using a self tracking entity model. ProductInstallation is a DTO which contains all the details about the product installation for a company.
The UserRoles entity holds the relationship in-between the Product-System Role-UserID.
As an example:
Product: Inventory
System Role : PurchasingUser
User ID : hasithaH <- (Suppose me)
using the below LINQ query, I can get the distinct UserIDs.
string[] userIDs = productInstallation.UserRoles
.Select(u=>u.UserID).Distinct().ToArray();
now I need to get all the User Profiles for the UserIDs I queried in above steps.
productInstallation.SystemUsers = context.SystemUsers.Select(u=> u.UserID ..???
In SQL point of view, this is the query I want:
Select * from SystemUsers where UserID in ('UserA','UserB','UserC')
How should I write a LINQ query to get this done?
You write it as follows:
var result = context.SystemUsers.Where(su =>
productInstallation.UserRoles.Any(ur => su.UserID == ur.UserId));
Or if both sources are not IQuerable from the same db:
string[] userIDs = productInstallation.UserRoles
.Select(u=>u.UserID).Distinct().ToArray();
var result = context.SystemUsers.Where(su =>
userIDs.Contains(su.UserID));
What you really want to do here is join the two tables. Using a Join you can do this in one query rather than executing two separate queries:
var systemUsers = from userRole in UserRoles
join systemUser in SystemUsers
on userRole.UserID equals systemUser.UserID
select systemUser;
You can try this:
productInstallation.SystemUsers =
context.SystemUsers.FindAll(u=> userIDs.Contains(u.UserID))

Categories