Reputation: 2763
I want to write a class which provides basically a list of entries. This entries can either be read from a database or are generated during application lifetime. This class should provide a way to filter this entries. Is it possible to implement the filters in a way that only one filter for both sources is needed?
For example:
interface IFilter
{
bool Filter(ILogEntry entry);
}
For LINQ with IEnumerable there is no problem to apply this as dynamic filters.
IEnumerable<IFilter> filters;
IEnumerable<ILogEntry> entries;
foreach(var filter in filters)
entries = entries.Where(p => filter.Filter(p));
But for Linq-To-Sql there are two problems I have no solution for:
It seems a little bit strange to me that the following code will actually execute the filter on the server. But if I use IFilter in this query which takes ILogEntry (which is implemented by LogEntry) as an argument the filter will be applied on client-side:
entities.Logs
.Select(p => new LogEntry() { Message = p.Message })
.Where(p => p.Message == "132");
Is there a way to write filters for ICollection and IQueryable and ensure that the filters for IQueryable will be executed on the SQL-Server?
Upvotes: 3
Views: 1384
Reputation: 1062660
The only way to apply that server side is by composing it as expression trees, for example:
interface IFilter {
public Expression<Func<ILogEntry, bool>> GetPredicate();
}
...
IQueryable<ILogEntry> entries = ...
foreach(var filter in filters) {
entries = entries.Where(filter.GetPredicate());
}
This then requires implementations such as:
public Expression<Func<ILogEntry, bool>> GetPredicate() {
return x => x.SomeField == 25;
}
Note: if you have an in-memory chink of data you can switch from IEnumerable<T>
to IQueryable<T>
by using .AsQueryable()
, which allows it to use an expression-tree locally.
Upvotes: 3