Min vs max in linq. - linq

Please help me understand why second line returns exception if my runs are empty.
I can take maxDate even if some of my schedules haven't runs
var maxDate = schedulingList.Max(p => p.Runs.Max(x => x.StartDate));
var minDate = schedulingList.Min(s => s.Runs.Min(r => r.StartDate));
what is the best way to get minDate ( null is posible ) ?
Great thanks in advance

You can select all your dates, do a DefaultIfEmpty on it, then get the min and max.
DefaultIfEmpty method will ensure that you have at least 1 item https://msdn.microsoft.com/en-us/library/bb360179(v=vs.110).aspx
var dates = schedulingList.SelectMany(p=>p.Runs.Select(t=>t.startDate)).DefaultIfEmpty();
var maxDate = dates.Max();
var minDate = dates.Min();

var minDate = schedulingList.Min(s => s.Runs.Min(r => r.StartDate)).FirstorDefault();
Hope this work,

Related

LINQ join multi tables in Lambda ex

I hope that someone can help me out here or to point me in the right direction:
I have an issue with this script from my SQL. This is what I have from the database and it comes out with success.
Script for water counter that has reminder for active period:
Select *
from WaterCounters
join WaterUsages on WaterUsages.WaterCounterId = WaterCounters.Id
join Periodes per on per.PeriodeId=WaterUsages.PeriodeId
where per.IsApproved = 1
Now I am trying to "translate/convert" into a LINQ query:
var waterCounter = Context.MyWaterCounter.Join(xx).ToList...
I am sure that I am doing it right but please advice me in how to "join more than one table" - thanks in advance.
Best regards,
Kvolle
UPDATED:
this is my script so far:
var waterCounter = Context.MyWaterCounter.Join(
Context.MyWaterUsages
.Where(x => x.WaterCounterId ==x.WaterCounterId)
.ToList());
Here is as I see it one table.
The tables in the database look like this:
It will look something like below
var waterCounter = Context.MyWaterCounter.Join(
Context.MyWaterUsages,
(WC) => WC.WaterCounterId,
(WU) => WU.Id,
(WC, WU) => new { WaterCounter = WC, WaterUsage = WU}
)
.Join(
Context.Periodes.Where(p => p.IsApproved=1),
(WUC) => WUC.WaterUsage.PeriodeId,
(P) => P.PeriodeId,
(WUC, P) => new { WaterCounter = WUC.WaterCounter, WaterUsage = WUC.WaterUsage, Period = P}
)
.ToList());

Filtering by Date (linq)

I have DateTime field named "repeat" in database. I want to take only records which Date in "repeat" is today.
I tried :
(...).Where(e => e.repeat.Value.Date.Day.Equals(DateTime.Now.Day));
or:
(...).Where(e => e.repeat.Value.Date.Day==DateTime.Now.Day);
but it doesn't work.
Any ideas?
Thanks,Kamil
"It doesn't work" is pretty vague, but currently you're checking the day of the week rather than the date. I would suggest using:
Date today = DateTime.Today;
var query = ....Where(e => e.repeat.Value.Date == today);
EDIT: It's not clear what the types involved here are - if repeat.Value is not itself a DateTime, you may want:
var query = ....Where(e => e.repeat.Value.Date.Date == today);
Give this a try:
(...).Where(e => (e.repeat >= DateTime.Today) && (e.repeat < DateTime.Today.AddDays(1)))
Compare short date ensures you the year/month/day are the same in one shot :
(...).Where(e => e.repeat.Value.Date.ToShortDateString() == DateTime.Now.ToShortDateString());
Expert Solution is: Use DbFunctions.CreateDateTime() in Linq Query.
var date = DateTime.Now.AddDays(-1).Date;
var actions = await _context.Set<Your_table>()
.AsNoTracking()
.Where(x => DbFunctions.CreateDateTime(x.YourColumn.Value.Year, x.YourColumn.Value.Month, x.YourColumn.Value.Day, 0, 0, 0) == date)
.ToListAsync();

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

LINQ to SQL, select targets with max date

I ended up with this horrible code below, I can't get a better result now.
What is a better way of doing that?
It's about this part of my database:
EDIT
A Patient has a Subscription to multiple MonitoringObjects. Target records refer to these Subscriptions. I want to retrieve the target records with the newest date per Subscription for a given Patient and a Category of MonitoringObjects. These target records may have different max dates, as Targets can be added for Subscriptions to MonitoringsObjects independently.
var subs = db.Subscriptions.Where(p => p.PatientID == patID).Where(p => p.MonitoringObject.Category.Name == "Medication");
var targets1 = from t in db.Targets
where subs.Contains(t.Subscription)
select t;
var maxTa = from t in db.Targets
group t by t.SubscriptionID
into g
select new
{
Ky = g.Key,
Date = g.Max(p => p.Date)
};
var targets2 = from t in targets1
where maxTa.Select(p => p.Ky).Contains( t.SubscriptionID ) &&
maxTa.Select(p => p.Date).Contains( t.Date )
select t;
I am not exactly sure what this is trying to achieve, or what your datamodel looks like, but something like this?
var subs = db.Subscriptions.Where(p => p.PatientID == patID).Where(p => p.MonitoringObject.Category.Name == "Medication");
var targets = subs
.SelectMany(s => s.Targets)
.Where(t => t.Date == t.Subscription.Targets.Max(_t => _t.Date))

LINQ: How to perform a conditional sum?

I have a LINQ Query that creates a new type that contains a days of week and a sum of hours worked.
My current (incorrect query) looks like this:
var resultSet = (from a in events
group a by a.Start.DayOfWeek into g
select new DaySummary
{
day = g.Key.ToString(),
hoursWorked = g.Any(p => p.Title == "Lunch") ? 0 :
Math.Round((g.Sum(
p => (Decimal.Parse((p.End - p.Start).TotalMinutes.ToString()))) / 60), 2)
}).ToList();
Hopefully you can see what Im trying to do. The Any method is not having the effect I'd like however. Basically I want to to sum up the hours worked, but if the title was "lunch" I want it to add 0.
The logic of this is just a little beyond me at the moment.
UPDATE
Ok, Im an idiot. Changes the query to this and it now works. Sorry.
var resultSet = (from a in events
group a by a.Start.DayOfWeek into g
select new DaySummary
{
day = g.Key.ToString(),
hoursWorked = Math.Round((g.Where(p => p.Title !="Lunch").
Sum(p => (Decimal.Parse((p.End - p.Start).TotalMinutes.ToString()))) / 60), 2)
}).ToList();
It seems each group is a sequence of 'periods' and you just want to ignore any 'lunch' periods in each calculation. In that case you just need to remove these from the sum using Where.
var hours = events
.GroupBy(e => e.Start.DayOfWeek)
.Select(g => new DaySummary {
day = g.Key.ToString(),
hoursWorked = Math.Round(
g.Where(p => p.Title != "Lunch")
.Sum(pd => (Decimal.Parse((pd.End - pd.Start).TotalMinutes.ToString())) / 60), 2)
}).ToList();

Resources