linq sum of multiple values - linq

i need to get the sum of billableHours and nonBillableHours.
this is my code.
var currentMonth = 10;
var userQuery =
from timeEntry in TimeEntries
join ta in Tasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth && timeEntry.DateEntity.Year == DateTime.Today.Year
select new
{
HoursEntered = timeEntry.HoursEntered,
Billable = ta.Billable
};
var localrows = userQuery.ToList();
var grouping = localrows.GroupBy(x => x.Billable);
var userList = grouping.Select(q => new
{
billableHours = q.Where(x=> x.Billable == true),
nonBillableHours = q.Where(x=> x.Billable != true)
});
i cannot seem to find a way to get the sum.
I need the sum of those two columns, so i can call them,
and calculate values i get from them.

When you need more than one aggregate, you can still get the result with a single query by using group by constant technique. Which in this specific case can be combined with conditional Sum:
var hoursInfo =
(from timeEntry in TimeEntries
join ta in Tasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth && timeEntry.DateEntity.Year == DateTime.Today.Year
group new { timeEntry.HoursEntered, ta.Billable } by 1 into g
select new
{
BillableHours = g.Sum(e => e.Billable ? e.HoursEntered : 0),
NonBillableHours = g.Sum(e => !e.Billable ? e.HoursEntered : 0),
}).FirstOrDefault();

You do not need to group them. Try this query:
var userQuery =
from timeEntry in TimeEntries
join ta in Tasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth
&& timeEntry.DateEntity.Year == DateTime.Today.Year
select new
{
HoursEntered = timeEntry.HoursEntered,
Billable = ta.Billable
};
var billableHours = userQuery
.Where(m => m.Billable) // Billable
.Select(m => m.HoursEntered)
.DefaultIfEmpty(0)
.Sum();
var nonBillableHours = userQuery
.Where(m => !m.Billable) // Non-bilable
.Select(m => m.HoursEntered)
.DefaultIfEmpty(0)
.Sum();

var currentMonth = 10;
var TimeEntries = new List<TimeEntry>() {
new TimeEntry(){TaskID = 1,DateEntity = DateTime.Now.AddDays(1),HoursEntered =2},
new TimeEntry(){TaskID = 2,DateEntity = DateTime.Now.AddDays(2),HoursEntered =3},
new TimeEntry(){TaskID = 3,DateEntity = DateTime.Now.AddDays(3),HoursEntered =2},
new TimeEntry(){TaskID = 4,DateEntity = DateTime.Now.AddDays(4),HoursEntered =4},
new TimeEntry(){TaskID = 5,DateEntity = DateTime.Now.AddDays(5),HoursEntered =2},
new TimeEntry(){TaskID = 6,DateEntity = DateTime.Now.AddDays(6),HoursEntered =6}
};
var UserTasks = new List<UserTask>(){
new UserTask(){TaskID = 1,Billable = true} ,
new UserTask(){TaskID = 2,Billable = false} ,
new UserTask(){TaskID = 3,Billable = true} ,
new UserTask(){TaskID = 4,Billable = false} ,
new UserTask(){TaskID = 5,Billable = true} ,
new UserTask(){TaskID = 6,Billable = false}
};
var userQuery =
from x in
(from timeEntry in TimeEntries
join ta in UserTasks on timeEntry.TaskID equals ta.TaskID
where timeEntry.DateEntity.Month == currentMonth && timeEntry.DateEntity.Year == DateTime.Today.Year
select new
{
HoursEntered = timeEntry.HoursEntered,
Billable = ta.Billable
})
group x by x.Billable into g
select new
{
IsBillable = g.Key,
Billabe = g.Where(t => t.Billable == true).Sum(x => x.HoursEntered),
NonBillable = g.Where(t => t.Billable == false).Sum(x => x.HoursEntered)
};
foreach (var item in userQuery.ToList())
{
Console.WriteLine(string.Format("{0} - {1}", item.IsBillable? "Billable":"Non-Billable",item.IsBillable?item.Billabe:item.NonBillable));
}

Related

Linq # Where clause with multiple condition

this is my export ui
this is my code:
var wrlist = db.Tbl_WorkRequest.ToList().Where(c => c.WR_Status == wrstatus &&
(wrtype.Length != 0) &&
c.WR_Family == wrfamily &&
wrfamily.Length!=0)
.Select(d => new {
WR_Title = d.WR_Title.ToString(),
WR_Type = d.WR_Type.ToString(),
WR_Family = d.WR_Family.ToString(),
WR_Status = d.WR_Status.ToString(),
WR_LocationAsset = d.WR_LocationAsset.ToString(),
WR_AssetName = d.WR_AssetName.ToString(),
WR_Requestor = d.WR_Requestor.ToString()
});
the problem is if I only choose zone in dropdownlist:family it generates correct list.
but when I choose dropdownlist:family&status it generates nothing.
this is the table:
I would change your code to check each filter criteria and add the appropriate filter, then convert to a list:
var wrq = db.Tbl_WorkRequest.AsQueryable();
if (wrstatus.Length > 0)
wrq = wrq.Where(wr => wr.WR_Status == wrstatus);
if (wrfamily.Length > 0)
wrq = wrq.Where(wr => wr.WR_Family == wrfamily);
var wrlist = wrq.Select(d => new {
WR_Title = d.WR_Title.ToString(),
WR_Type = d.WR_Type.ToString(),
WR_Family = d.WR_Family.ToString(),
WR_Status = d.WR_Status.ToString(),
WR_LocationAsset = d.WR_LocationAsset.ToString(),
WR_AssetName = d.WR_AssetName.ToString(),
WR_Requestor = d.WR_Requestor.ToString()
})
.ToList();

How to do a cascading IGrouping?

I'm trying to do a cascading groupby, but I can't find a way to get the proper index in the end (the .ElementAt(0) in the end of the code is wrong, in all 3 levels of hierarchy).
//Level
//---|Category
//---|---|Family
//---|---|---|Type
//---|---|---|---|Leaf
var leafs = queryLeafs.ToList();
foreach (var leaf in leafs)
{
//Get Type
var leafAttr = leaf.ObjectsEav.First(eav => eav.Attribute.Name == "parent");
long typeId = leafAttr.Value.Value;
leaf.Type = universe.First(o => o.Id == typeId);
//Family
var typeAttr = leaf.Type.ObjectsEav.First(eav => eav.Attribute.Name == "parent");
long familyId = typeAttr.Value.Value;
leaf.Family = universe.First(o => o.Id == familyId);
//Category
var familyAttr = leaf.Family.ObjectsEav.First(eav => eav.Attribute.Name == "parent");
long categoryId = familyAttr.Value.Value;
leaf.Category = universe.First(o => o.Id == categoryId);
}
var groupType = leafs.GroupBy(leaf => leaf.Type);
var groupFamily = groupType.GroupBy(t => **t.ElementAt(0)**.Family);
var groupCategory = groupFamily.GroupBy(f => **f.ElementAt(0).ElementAt(0)**.Category);
Can someone provide a light in my dark path?
If you have any suggestion on how to improve this question, I would appreciate with all my heart.

Convert query to lambda

I want to know how can I write this query:
var query = from p in context.DimProduct
from psc in context.DimProductSubcategory
// on psc.ProductCategoryKey equals pc.ProductCategoryKey
where psc.EnglishProductSubcategoryName == subCategoryName
&& psc.ProductSubcategoryKey == p.ProductSubcategoryKey
select new DimProductDTO
{
ProductKey = p.ProductKey,
ProductSubcategoryKey = p.ProductSubcategoryKey,
EnglishProductName = p.EnglishProductName,
Size = p.Size,
StandardCost = p.StandardCost
};
I tried some queries, but no success. My problem is that I don't know how to have access to DimProduct and DimProductSubcategory.
Any suggestions?
context.DimProduct
.SelectMany(p => new { p, psc = context.DimProductSubcategory })
.Where(x => x.psc.EnglishProductSubcategoryName == subCategoryName
&& x.psc.ProductSubcategoryKey == x.p.ProductSubcategoryKey)
.Select(x => new DimProductDTO {
ProductKey = x.p.ProductKey,
ProductSubcategoryKey = x.p.ProductSubcategoryKey,
EnglishProductName = x.p.EnglishProductName,
Size = x.p.Size,
StandardCost = x.p.StandardCost })
However, you're not selecting anything from DimProductSubcategory, so I think the same can be done using Any() extension method:
context.DimProduct
.Where(x => context.DimProductSubcategory
.Any(y => y.EnglishProductSubcategoryName == subCategoryName
&& y.ProductSubcategoryKey == x.ProductSubcategoryKey))
.Select(x => new DimProductDTO {
ProductKey = x.ProductKey,
ProductSubcategoryKey = x.ProductSubcategoryKey,
EnglishProductName = x.EnglishProductName,
Size = x.Size,
StandardCost = x.StandardCost });
It should generate IN SQL statement within the query.
That is not exactly same query, but it produces same result via inner join (I believe that is more efficient than cross join)
context.DimProduct
.Join(context.DimProductSubcategory
.Where(x => x.EnglishProductSubcategoryName == subCategoryName),
p => ProductSubcategoryKey,
psc => ProductSubcategoryKey,
(p,psc) => new { p, psc })
.Select(x => new DimProductDTO {
ProductKey = x.p.ProductKey,
ProductSubcategoryKey = x.p.ProductSubcategoryKey,
EnglishProductName = x.p.EnglishProductName,
Size = x.p.Size,
StandardCost = x.p.StandardCost })
Also your original query can be rewritten as
var query = from p in context.DimProduct
join psc in context.DimProductSubcategory
on p.ProductSubcategoryKey equals psc.ProductSubcategoryKey
where psc.EnglishProductSubcategoryName == subCategoryName
select new DimProductDTO {
ProductKey = p.ProductKey,
ProductSubcategoryKey = p.ProductSubcategoryKey,
EnglishProductName = p.EnglishProductName,
Size = p.Size,
StandardCost = p.StandardCost
};
Generated SQL will look like:
SELECT [t0].[ProductKey], [t0].[ProductSubcategoryKey]
FROM [DimProduct] AS [t0]
INNER JOIN [DimProductSubcategory] AS [t1]
ON [t0].[EnglishProductSubcategoryName] = [t1].[ProductSubcategoryKey]
WHERE [t1].[EnglishProductSubcategoryName] = #p0

Entity fails on simulataneous AJAX posts

I have an action that updates the database based on a Jquery Droppable/Sortable. The first AJAX post works fine, but the second one gives me the error:
New transaction is not allowed because there are other
threads running in the session.
It's being posted to 2 separate actions on the same controller, using the same UnitOfWork in the controller. Not sure what I have to do to fix this.
EDIT: these are the two service methods being called:
public void NavItemSort(List<string> orderArray, string navID, string subNavID)
{
var newOrderArray = orderArray.Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
var orderArrayIDs = newOrderArray.Select(x => x.Replace("ContentItem", "")).ToList();
var itemToBeSorted = Convert.ToInt32(orderArrayIDs.FirstOrDefault());
var itemContext = cmsUnitOfWork.NavigationItems.Find().Where(x => x.ID == itemToBeSorted).ToList().FirstOrDefault();
var currentSortOrder = cmsUnitOfWork.NavigationItems.Find()
.Where(x => x.NavID == itemContext.NavID &&
(itemContext.ParentID == null) ? x.ParentID == null :
x.ParentID == itemContext.ParentID).ToList();
var existingItems = currentSortOrder.Select(x => x.ID).ToList();
List<string> existingItemsString = existingItems.ConvertAll<string>(x => x.ToString()).ToList();
var newNavItemID = existingItemsString.Except(orderArray).FirstOrDefault();
var currentSortOrderExcept = currentSortOrder.Where(x => x.ID != Convert.ToInt32(newNavItemID));
foreach (var x in currentSortOrderExcept)
{
int sortOrderInt = orderArrayIDs.IndexOf(orderArrayIDs.Where(z => int.Parse(z) == x.ID).ToList().FirstOrDefault()) + 1;
NavigationItem navigationItem = new NavigationItem()
{
HasChild = x.HasChild,
Level = x.Level,
NavID = x.NavID,
ID = x.ID,
ParentID = x.ParentID,
PageID = x.PageID,
URL = x.URL,
Title = x.Title,
SortOrder = sortOrderInt,
};
if (navigationItem.SortOrder != null && navigationItem.SortOrder != 0)
{
cmsUnitOfWork.NavigationItems.Update(x, navigationItem);
}
}
cmsUnitOfWork.Commit();
}
public void NavItemAdd(List<string> orderArray, string NavID, string subNavID){
var newOrderArray = orderArray.Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
var orderArrayIDs = newOrderArray.Select(x => x.Replace("ContentItem", "")).ToList();
NavID = NavID.Replace("nav", "");
int NavIDInt = int.Parse(NavID);
int subNavIDInt = int.Parse(subNavID);
var existingNavItems = cmsUnitOfWork.NavigationItems.Find().Where(x => x.NavID == NavIDInt && x.ParentID == subNavIDInt).ToList();
int currentSortOrder = 0;
if (existingNavItems.Count() != 0)
{
currentSortOrder = existingNavItems.Max(x => x.SortOrder);
}
var existingItems = existingNavItems.Select(x => x.ID).ToList();
List<string> existingItemsString = existingItems.ConvertAll<string>(x => x.ToString()).ToList();
var newNavItemID = orderArray.Except(existingItemsString).FirstOrDefault();
int newNavIDInt = int.Parse(newNavItemID);
var newNavItemList = cmsUnitOfWork.NavigationItems.Find().Where(x => x.ID == newNavIDInt).ToList();
var newNavItem = newNavItemList.FirstOrDefault();
var parentNav = cmsUnitOfWork.NavigationItems.Find().Where(x => x.ID == subNavIDInt).ToList().FirstOrDefault();
NavigationItem navigationItemUpdated = new NavigationItem()
{
ID = newNavItem.ID,
Level = 2,
NavID = NavIDInt,
PageID = newNavItem.PageID,
Title = newNavItem.Title,
URL = newNavItem.URL,
ParentID = subNavIDInt,
SortOrder = currentSortOrder + 1
};
cmsUnitOfWork.NavigationItems.Update(newNavItem, navigationItemUpdated);
cmsUnitOfWork.Commit();
}
I'm guessing you started a transaction against that context and you never dispose of it not commit it. Just a guess though as you didn't Los any code (please post code)
Maybe you have declared cmsUnitOfWork as static variable? Context must be created and destroyed on each request

How to write a LINQ statement with a GroupBy condition

I have this LINQ statement as follows;
var RequestList = (from emp in _employeeIds
from x in db.AnnualLeaveBookeds
where x.EmployeeId == emp
orderby x.AnnualLeaveDate
select new RequestInfo
{
AnnualLeaveBookedId = x.AnnualLeaveBookedId,
AnnualLeaveDate = x.AnnualLeaveDate,
MorningOnlyFlag = x.MorningOnlyFlag,
AfternoonOnlyFlag = x.AfternoonOnlyFlag,
Forename = x.Employee.Forename,
Surname = x.Employee.Surname,
EmployeeId = x.Employee.EmployeeId,
RequestDate = x.RequestDate,
CancelRequestDate = x.CancelRequestDate,
ApprovedFlag = (x.ApprovalDate.HasValue && x.ApproverId != Employee.LoggedInUser.EmployeeId),
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty,
FontColour = "Black"
})
.ToList();
For every RequestInfo I return a FontColour property of Black.
However if I have 2 or more RequestInfo objects with the same AnnualLeaveDate, I want the FontColour to be set to red.
How do I rewrite this query to do that?
Try something like this:
var RequestList = (
from emp in _employeeIds
from x0 in db.AnnualLeaveBookeds
where x0.EmployeeId == emp
orderby x0.AnnualLeaveDate
group x0 by x0.AnnualLeaveDate into xs
from x in xs
select new RequestInfo
{
AnnualLeaveBookedId = x.AnnualLeaveBookedId,
AnnualLeaveDate = x.AnnualLeaveDate,
MorningOnlyFlag = x.MorningOnlyFlag,
AfternoonOnlyFlag = x.AfternoonOnlyFlag,
Forename = x.Employee.Forename,
Surname = x.Employee.Surname,
EmployeeId = x.Employee.EmployeeId,
RequestDate = x.RequestDate,
CancelRequestDate = x.CancelRequestDate,
ApprovedFlag = (x.ApprovalDate.HasValue
&& x.ApproverId != Employee.LoggedInUser.EmployeeId),
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty,
FontColour = xs.Count() > 1 ? "Red" : "Black"
}).ToList();

Resources