I have a linq query which accepts a list of date and port combinations. This query has to return data from a table, CruiseCalendar, where these combinations are found, but only when the count is greater than one. I cant work out the groupby and count syntax. var shipRendezvous is where I'm stuck.
var dateAndPort = (from r in context.CruiseCalendar
where r.ShipId == shipId
&& r.CruiseDayDate >= dateRange.First
&& r.CruiseDayDate <= dateRange.Last
select new DateAndPort
{
Date = r.CruiseDayDate,
PortId = r.PortId
});
var shipRendezvous = (from r in context.CruiseCalendar
where (dateAndPort.Any(d => d.Date == r.CruiseDayDate
&& d.PortId == r.PortId))
orderby r.CruiseDayDate // (Added since first posting)
select r).ToList();
regards, Guy
If I understood you correctly, you are filterting for every set which matches any of the results of dateAndPort and then want to group it by itsself to get a count. Of the grouping results you only want those resultsets, which occur more then once.
var shipRendezvous = (from r in context.CruiseCalendar
where (dateAndPort.Any(d => d.Date == r.CruiseDayDate
&& d.PortId == r.PortId))
select r)
.GroupBy(x => x.CruiseDayDate) //Groups by every combination
.Where(x => x.Count() > 1) //Where Key count is greater 1
.ToList();
Based on your comment, you want to flatten the list again. To do so, use SelectMany():
var shipRendezvous = (from r in context.CruiseCalendar
where (dateAndPort.Any(d => d.Date == r.CruiseDayDate
&& d.PortId == r.PortId))
select r)
.GroupBy(x => x.CruiseDayDate) //Groups by every combination
.Where(x => x.Count() > 1) //Where Key count is greater 1
.SelectMany(x => x)
.ToList();
Related
Having a table Entities with a column type (between other columns) how can I select only n entities from type A and m entities from type b in a single linq query where clause? Is it possible?
I am looking for something like this:
var x = from s in db.Entities
where s.type == `A` && (????) < n
|| s.type == `B` && (????) < m
select s
Current solution with combined queries:
var x = entities.Where(e => e.type == `A`).Take(n).Union(
entities.Where(e => e.type == `B`).Take(m));
You could use GroupBy:
var x = db.Entities.GroupBy(x => x.type)
.Where(g => g.Key == "A" || g.Key == "B")
.SelectMany(g => g.Key == "A" ? g.Take(n) : g.Take(m));
But I don't know why you don't like your Union-based solution - it should result in just one query sent to the database anyway.
I'm using LINQPad to evaluate my linq query. My query goes like this:
from o in MyTableFirst
join p in MyTableSecond on o.TheName equals p.TheName
where p.TheName == "CBA-123" && !p.Removed &&
(o.ReturnPeriod ==100 || o.ReturnPeriod ==10)
select new {
HMax1 = o.MaxValue1,
HMax2 = o.MaxValue2,
HMax3 = o.MaxValue3
}
This query can return 0 or some number of rows.
In LINQPad, it return me something like this:
HMax1 HMax2 HMax3
21.1 null 22.5
null 24.6 11.5
Now, how am I going to get the Maximum value out for these return rows & columns?
I'm expecting return of 24.6.Thank You
How about this:
(from o in db.MyTableFirsts
join p in db.MyTableSeconds on o.TheName equals p.TheName
where p.TheName == "CBA-123" && !p.Removed &&
(o.ReturnPeriod == 100 || o.ReturnPeriod == 10)
select new
{
Maximum = Math.Max(
Math.Max((float)(o.MaxValue1 ?? 0), (float)(o.MaxValue2 ?? 0)),
(float)(o.MaxValue3 ?? 0)
)
}).OrderByDescending(o => o.Maximum).FirstOrDefault();
Or instead of .OrderByDescending(o => o.Maximum).FirstOrDefault(), you can use .Max(o => o)
Try this:
(
from o in MyTableFirst
join p in MyTableSecond on o.TheName equals p.TheName
where p.TheName == "CBA-123" && !p.Removed &&
(o.Level ==100 || o.Level ==10)
//combine all of the numbers into one list
let listOfNumbers = new List<double?>{o.MaxValue1,o.MaxValue2,o.MaxValue3}
//select the list
select listOfNumbers
)
.SelectMany(c => c) //combine all the lists into one big list
.Max(c => c) //take the highst number
Given the query below
public TrainingListViewModel(List<int> employeeIdList)
{
this.EmployeeOtherLeaveItemList =
CacheObjects.AllEmployeeOtherLeaves
.Where(x => x.OtherLeaveDate >= Utility.GetToday() &&
x.CancelDate.HasValue == false &&
x.OtherLeaveId == Constants.TrainingId)
.OrderBy(x => x.OtherLeaveDate)
.Select(x => new EmployeeOtherLeaveItem
{
EmployeeOtherLeave = x,
SelectedFlag = false
}).ToList();
}
I want to put in the employeeIdList into the query.
I want to retrieve all of the x.OtherLeaveDate values where the same x.OtherLeaveDate exists for each join where x.EmployeeId = (int employeeId in employeeIdList)
For example if there are EmployeeIds 1, 2, 3 in employeeIdList and in the CacheObjects.AllEmployeeOtherLeaves collection there is a date 1/1/2001 for all 3 employees, then retreive that date.
If I read you well it should be something like
var grp = this.EmployeeOtherLeaveItemList =
CacheObjects.AllEmployeeOtherLeaves
.Where(x => x.OtherLeaveDate >= Utility.GetToday()
&& x.CancelDate.HasValue == false
&& x.OtherLeaveId == Constants.TrainingId
&& employeeIdList.Contains(x.EmployeeId)) // courtesy #IronMan84
.GroupBy(x => x.OtherLeaveDate);
if (grp.Count() == 1)
{
var result = g.First().Select(x => new EmployeeOtherLeaveItem
{
EmployeeOtherLeave = x,
SelectedFlag = false
})
}
First the data is grouped by OtherLeaveDate. If the grouping results in exactly one group, the first (and only) IGrouping instance is taken (which is a list of Leave objects) and its content is projected to EmployeeOtherLeaveItems.
To the where statement add "&& employeeIdList.Contains(x.EmployeeId)"
I need to thank #IronMan84 and #GertArnold for helping me along, and I will have to admonish myself for not being clearer in the question. This is the answer I came up with. No doubt it can be improved but given no one has responded to say why I will now tick this answer.
var numberOfEmployees = employeeIdList.Count;
var grp = CacheObjects.AllEmployeeOtherLeaves.Where(
x =>
x.OtherLeaveDate >= Utility.GetToday()
&& x.CancelDate.HasValue == false
&& x.OtherLeaveId == Constants.TrainingId
&& employeeIdList.Contains(x.EmployeeId))
.GroupBy(x => x.OtherLeaveDate)
.Select(x => new { NumberOf = x.Count(), Item = x });
var list =
grp.Where(item => item.NumberOf == numberOfEmployees).Select(item => item.Item.Key).ToList();
Summary
I have a list of Transactions. Using Linq, I want to get a sum of the Cost and sum of the Quantity from this list in one query.
Grouping
My first thought is to use grouping - but I don't really have a key that I want to group on, I want just one group with the results from the whole list. So, I happen to have a property called "Parent" that will be the same for all of the transactions, so I'm using that to group on:
var totalCostQuery =
(from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
group t by t.Parent into g
select new
{
TotalCost = g.Sum(t => t.Cost.GetValueOrDefault()),
TotalQuantity = g.Sum(t => t.Quantity.GetValueOrDefault())
});
Grouping by t.Parent seems like it could be wrong. I really don't want to group at all, I just want the sum of t.Quantity and sum of t.Cost.
Is that the correct way to get a sum of two different properties or can it be done in a different way.
Assuming this is Linq to SQL or Entity Framework, you can do that:
var totalCostQuery =
(from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
group t by 1 into g
select new
{
TotalCost = g.Sum(t => t.Cost),
TotalQuantity = g.Sum(t => t.Quantity)
});
Note that you don't need to use GetValueOrDefault, null values will be ignored in the sum.
EDIT: not sure this works with Linq to NHibernate though...
Note that if you're using Linq to objects, the solution above won't be efficient, because it will enumerate each group twice (once for each sum). In that case you can use Aggregate instead:
var transactions =
from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
select t;
var total =
transactions.Aggregate(
new { TotalCost = 0.0, TotalQuantity = 0 },
(acc, t) =>
{
TotalCost = acc.TotalCost + t.Cost.GetValueOrDefault(),
TotalQuantity = acc.TotalQuantity + t.Quantity.GetValueOrDefault(),
});
Basically I want to write a linq query to order the number of days they were present. But I have got these six time filters- Today,Yesterday,current month,previous month,current year,previous year.So now I have this queries which I have simplified but before these queries below, I actually order these employees on different aspects and after ordering it as you can see I assign rank and then at the same time find out his count(which may or may not be used to rank them later)-
var result=datacontext.Employee(c=>c.Company.Id==companyId).Select((k, index) => new EmployeeDTO()
{
EmployeeId=k.Employee.Id,
CompanyId=Employee.Company.Id
PresentCount=(from e in employeeAttendance
where d.RecNum == k.recnum
&& d.date_present.Year == DateTime.Today.Year
&& d.date_present.Month == DateTime.Today.Month
&& d.date_present.Day == DateTime.Today.Day
select d).Count()
}
So now when the filter is say previous year I have -
var result=datacontext.Employee(c=>c.Company.Id==companyId).Select((k, index) => new EmployeeDTO()
{
Position=
EmployeeId=k.Employee.Id,
CompanyId=Employee.Company.Id
PresentCount=(from e in employeeAttendance
where d.RecNum == k.recnum
&& d.date_present.Year == (DateTime.Today.Year-1)
}
and if have it on Current Month I have -
var result=datacontext.Employee(c=>c.Company.Id==companyId).Select((k, index) => new EmployeeDTO()
{
EmployeeId=k.Employee.Id,
CompanyId=Employee.Company.Id
PresentCount=(from e in employeeAttendance
where d.RecNum == k.recnum
&& d.date_present.Month == DateTime.Today.Month
&& d.date_present.Year == DateTime.Today.Year
}
I basically want to combine all these in one query with basically having like a dynamic clause for finding out the present count ?
Just create a simple wrapper. Eg:
IQueryable<EmployeeDTO> GetEmployeeCount(Expression<Func<DateTime, bool>> pred)
{
var result=datacontext.Employee(c=>c.Company.Id==companyId).
Select((k, index) => new EmployeeDTO()
{
EmployeeId=k.Employee.Id,
CompanyId=Employee.Company.Id,
PresentCount=(from e in employeeAttendance
where d.RecNum == k.recnum && pred(d.date_present)
select d).Count()
});
return result;
}
Usage:
var r = GetEmployeeCount(d => d.Year == (DateTime.Today.Year-1));
var r = GetEmployeeCount(
d => d.Month == DateTime.Today.Month && d.Year == DateTime.Today.Year);