I have the following code (note that this is truncated to the corresponding part, the actual request is much more complicated):
public IQueryable<Menu> GetMenus(DateTime lastUpdate) { ... result = GetAll().Where(m => lastUpdate < m.LastModified) .ForEach(m => m.Descriptions = m.Descriptions .Where(d => lastUpdate < d.LastModified)); ... enter code here
This is a function within the update service program for an application to get any menu that has either changed itself or any of its descriptions since the last update service call.
Clarification: the function should return every menu that has changed since the last call. In addition, he needs to return each changed description of each changed menu. but he must leave the Description unchanged.
As an example:
Menu menuA = new Menu() { LastModified = new DateTime(2014, 12, 24), Descriptions = new List<Description>() { new Description() { LastModified = new DateTime(2014, 12, 24) }, new Description() { LastModified = new DateTime(2014, 12, 01) } } }; Menu menuB = new Menu() { LastModified = new DateTime(2014, 12, 20), Descriptions = new List<Description>() { new Description() { LastModified = new DateTime(2014, 12, 01) } } };
Now, when I call the update function with a new DateTime (2014, 12, 15), this is the structure that it should return:
List<Menu>: { menuA: { LastModified: DateTime(2014, 12, 24), Descriptions: List<Description> { Description: { LastModified: DateTime(2014, 12, 24), } } }, menuB: { LastModified: DateTime(2014, 12, 20), Descriptions: List<Description> {} } }
With ForEach () it looks like this:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action) { ... // Parameter check foreach (T item in source) { action(item); } return source; }
Menus and descriptions were automatically created by the entity infrastructure as follows:
public partial class Menu { ... public System.DateTime LastModified { get; set; } public virtual ICollection<Description> Descriptions { get; set; } ... } public partial class Description { ... public System.DateTime LastModified { get; set; } public virtual Menu Menu { get; set; } ... }
Unfortunately, the Where
function returns an IEnumerabley<Description>
, which cannot be included inside the ICollection<Description>
defined by the entity infrastructure.
When I try to do this myself, I get a runtime error in the header:
m => m.Descriptions = (ICollection<Description>)m.Descriptions.Where(...)
Now I understand why this error occurs. Expression Description Where
has not yet been evaluated, so what is supposed to be distinguished from ICollection<Description>
is not yet IEnumerable<Description>
, but whereEnumerableIterator is. Right now, I am throwing the Where
expression into a list that immediately gets evaluated, and then discarded on ICollection<Description>
.
m => m.Descriptions = (ICollection<Description>)m.Descriptions.Where(...).ToList()
However, this is just a workaround that kills the benefits of LINQ expression and is also just ugly. I could write an extension method WhereCollection<T>(...)
calling Where<T>
and returning ICollection<T>
, but that would not change very much, I would have to throw inside, which either leads to the same error , or calls ToList()
internally.
Is there an elegant solution to this problem without causing the Where
evaluate before the LINQ statement is evaluated?