I'm trying to learn LINQ - the hard way.
I have a few entities which all are connected in sequence
Department -> Groups -> Works -> project
project has a startdate (and an end date)
I'm trying to get the startdate of the Group with the first startdate so to speak.
I've tried:
Department.Groups.Select(g => g.Works.Select(w => w.project.StartDate).Min())
and various variations thereof.
The problem being it returns a list in a list in a list, and I'm getting dizzy from just thinking about it :)
I've tried to work my way backwards from
g.Works.Select(w=> w.Project.StartDate).Min() which gives me the lowest date for Works
Any help is greatly appreciated
Flatten your List with SelectMany and then apply Min like:
var minDate = Department.Groups
.SelectMany(g => g.Works.Select(w => w.project.StartDate))
.Min();
That will return the minimum date for all the Works under all Groups.
If you just want the date then Habib's flatten solution is good. If you want the whole record you can order by and then take the first record, like this:
Department
.Groups
.OrderBy(g => g.Works.Select(w => w.project.StartDate))
.FirstOrDefault()
Related
i want to apply where clause on COLID column and wish to take the very last value w.r.t that COLID, e.g in COLID 1 case the last returned value should not be NULL and in COLID 2 it would be 30, against each ENTRYID
I can do it well in SQL, look at the query and data:
You can edit your question to append code rather than pasting it into comments. Paste the code into the question and use the "{}" button in the editor to code format.
You can group and sort items in Linq without too much issue.
context.Entries
.GroupBy(x => x.EntryID)
.Select(x => x.OrderByDescending(y => y.ColID).FirstOrDefault())
.ToList();
GroupBy defines what columns make up the unique grouping. In your case if you want the latest Entry then the EntryId would be enough to define what to group on. This will form the Key for each group. From there we use Select to tell it what to select from each group. The group will be all entries of that EntryID so we order by the ColID descending so the biggest one is first, then use FirstOrDefault to take the largest one. The ToList() at the end materializes the result to retrieve the latest ColID version of each EntryID.
Edit: If you want to only consider non-null values:
context.Entries
.Where(x => x.ColValueId != null)
.GroupBy(x => x.EntryID)
.Select(x => x.OrderByDescending(y => y.ColID).FirstOrDefault())
.ToList();
Linq is a bit different than SQL and can have some limitations when used with EF because EF will ultimately need to convert it to SQL. Still, it is well worth reading up on Linq because it is a very powerful tool when working with objects and it allows EF to do a lot of the heavy lifting.
Hi I'm having trouble retrieving distinct dates from a database. In this database I have several events on any particular day and results show a list of events with the same date / 'StartDate' field. How could I retrieve just the distinct days. I've tried:
ICollection result;
result= client.GetEventInstances().Select(x => x.StartDate).Distinct();
I expect to see just one distinct date along with just the first event for that date only.
Then you need to group on the events and get the first item out of every date:
client.GetEventInstances()
.GroupBy(k => k.StartDate.Date)
.ToDictionary(k => k.Key, v => v.First())
Well, I managed to search and find a solution for my needs, it wont suit everyone of course. Thanks for the time people gave me on this, always appreciated
ICollection<EventInstance> result;
result = client.GetEventInstances();
IEnumerable<EventInstance> distinctDate = result
.GroupBy(e => e.StartDate.Date)
.Select(group => group.First());
The relationship between them is one order to many journals. Now I want to get the sum of all pending orders (or records that are flagged as false under IsDelivered in Order entity).
So far, I have this query but can't seem to get working when I add .Sum()
Orders
.Where(o => o.IsDelivered == false)
.Select(o => new {
pendingOrders = o.Journals.Sum(j => j.TotalAmount)
})
So far this results to:
In a nutshell, how can I get the sum of them? If query needs to be altered or should be a new one. It is welcome. Any help would be much appreciated. Thanks!
You can do it in several ways:
You could add Sum(n => n.pendingOrders) to the end of your query to add up the values, or
You could use SelectMany before Select, and use Sum instead of Select.
Either of the two approaches is going to work.
In this case, it is easiest to use SelectMany (MSDN) to flatten your collections, then use Sum:
Orders.Where(o => !o.IsDelivered).SelectMany(o => o.Journals).Sum(j => j.TotalAmount);
I have a very simple query which selects items from a table based on matching the month and then grouping by day. These groups are then used as a data source for a repeater which outputs the group elements as entries "per day".
The problem is that days that don't exist (i.e. there's no group for) will naturally not be displayed, so things for the 6th and 8th, when there's nothing for the 7th, will be seen directly next to each other (think of a calendar view). The question is, given my query below, how could I insert groups with no elements, even when there's no entry for that day?
IQueryable events =
Events
.Where(i => i.Date.Month == date.Month)
.GroupBy(i => i.Date.Day);
I can do this figuring out after the fact, but can I account for it to get the result set at once? Or can a previous tried & tested approach be recommended?
Create your result set like this:
var date = ...;
var events = Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month))
.ToDictionary(
day => new DateTime(date.Year, date.Month, day),
day => new List<Event>());
Then insert into it like this:
var query = Events
.Where(e => e.Date.Year == date.Year)
.Where(e => e.Date.Month == date.Month);
foreach (var e in query)
events[e.Date].Add(e);
If you really want to do this server-side as part of the query, you'll either need to (A) send the list of dates you're interested in as part of the query, or (B) use DBMS-specific functions to construct the set of days you're interested in server-side.
Specific to (B) and SQL, there are things like this: Get the first and last date of next month in MySQL
I personally would just do this client-side. The database query gets whatever data your implementation needs to extract from the database; the user gets whatever information your view needs. To query the database for the data you need to create your view, you don't actually need to know the list of dates in your month, so it really shouldn't be part of the query.
I have a bunch of rows grouped on an attribute called MyID. Now I want the one row from each group where the StatusDate attribute is the highest in that one group.
This is what I've come up with.
rows.Select(x => x.Where(y => y.StatusDate == x.Max(z => z.StatusDate)).First())
With a bit more explanation:
rows.Select(x => // x is a group
x.Where(y => // get all rows in that group where...
// the status date is equal to the largest
// status date in the group
y.StatusDate == x.Max(z => z.StatusDate)
).First()) // and then get the first one of those rows
Is there any faster or more idiomatic way to do this?
One alternative would be to use:
rows.Select(x => x.OrderByDescending(y => y.StatusDate).First());
... and check that the query optimiser knows that it doesn't really need to sort everything. (This would be disastrous in LINQ to Objects, but you could use MaxBy from MoreLINQ in that case :)
(Apologies for previous version - I hadn't fully comprehended the grouping bit.)
Don't know if this is Linq to SQL, but if it is, you could alternatively accomplish via a rank() function in SQL (rank each group by date, then select the first ranked row from each), then call this as a stored proc from LINQ. I think that's an approch that is becoming more idiomatic as people hit the bounderies of LINQ2SQL...