When is ObjectQuery really an IOrderedQueryable? - c#

Applied to entity framework, the extension methods Select() and OrderBy() both return an ObjectQuery, which is defined as:
public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>,
IQueryable<T>, <... more interfaces>
The return type of Select() is IQueryable<T> and that of OrderBy is IOrderedQueryable<T>. So you could say that both return the same type but in a different wrapper. Luckily so, because now we can apply ThenBy after OrderBy was called.
Now my problem.
Let's say I have this:
var query = context.Plots.Where(p => p.TrialId == 21);
This gives me an IQueryable<Plot>, which is an ObjectQuery<Plot>. But it is also an IOrderedQueryable:
var b = query is IOrderedQueryable<Plot>; // True!
But still:
var query2 = query.ThenBy(p => p.Number); // Does not compile.
// 'IQueryable<Plot>' does not contain a definition for 'ThenBy'
// and no extension method 'ThenBy' ....
When I do:
var query2 = ((IOrderedQueryable<Plot>)query).ThenBy(p => p.Number);
It compiles, but gives a runtime exception:
Expression of type 'IQueryable`1[Plot]' cannot be used for parameter of type 'IOrderedQueryable`1[Plot]' of method 'IOrderedQueryable`1[Plot] ThenBy[Plot,Nullable`1](IOrderedQueryable`1[Plot], Expressions.Expression`1[System.Func`2[Plot,System.Nullable`1[System.Int32]]])'
The cast is carried out (I checked), but the parameter of ThenBy is still seen as IQueryable (which puzzles me a bit).
Now suppose some method returns an ObjectQuery<Plot> to me as IQueryable<Plot> (like Select()). What if I want to know whether it is safe to call ThenBy on the returned object. How can I figure it out if the ObjectQuery is "real" or a "fake" IOrderedQueryable without catching exeptions?

Expression Trees are genuinely good fun! (or perhaps I'm a little bit of a freak) and will likely become useful in many a developer's future if Project Roslyn is anything to go by! =)
In your case, simple inherit from MSDN's ExpressionVisitor, and override the VisitMethodCall method in an inheriting class with something to compare m.MethodInfo with SortBy (i.e. if you're not too fussy simply check the name, if you want to be fussy use reflection to grab the actual SortBy MethodInfo to compare with.
Let me know if/what you need examples of, but honestly, after copy/pasting the ExpressionVisitor you'll probably need no more than 10 lines of non-expression-tree code ;-)
Hope that helps

Although Expression Trees are good fun, wouldn't in this case the simple solution be to use OrderBy rather than ThenBy?
OrderBy is an extension on IQueryable and returns an IOrderedQueryable.
ThenBy is an extension on IOrderedQueryable and returns an IOrderedQueryable.
So if you have a IQueryable (as in your case above, where query is an IQueryable) and you want to apply an initial ordering to it, use OrderBy. ThenBy is only intended to apply additional ordering to an already ordered query.
If you have a LINQ result of some kind, but you aren't sure if it is an IQueryable or an IOrderedQueryable and want to apply additional filtering to it, you could make two methods like:
static IOrderedQueryable<T, TKey> ApplyAdditionalOrdering<T, TKey>(this IOrderedQueryable<T, TKey> source, Expression<Func<T, TFilter>> orderBy)
{
return source.ThenBy(orderBy);
}
And
static IOrderedQueryable<T, TKey> ApplyAdditionalOrdering<T, TKey>(this IQueryable<T> source, Expression<Func<T, TFilter>> orderBy)
{
return source.OrderBy(orderBy);
}
The compiler will figure out the correct one to call based on the compile-time type of your query object.

Related

Would using an extension method to query an IEnumerable be equivalent to using IQueryable?

I understand the main difference between IQueryable and IEnumerable. IQueryable executes the query in the database and returns the filtered results while IEnumerable brings the full result set into memory and executes the filtering query there.
I don't think using an extension method to query on the initial assignment of a variable will cause it to be executed in the database like IQueryable, but I just wanted to make sure.
This code will cause the full result set of People to be returned from the database, and then the filtering is done in memory:
(The People property on the context is of type DbSet)
IEnumerable<Person> people = context.People;
Person person = people.Where(x => x.FirstName == "John");
Even though I am adding the filtering below as an extension method before assigning the item to my variable, I'm assuming this code should work the same way as the code above, and bring back the full result set into memory before filtering it, right?
Person person = context.People.Where(x => x.FirstName == "John");
EDIT:
Thanks for the replies guys. I modified the code example to show what I meant (removed the IEnumerable in the second paragraph of code).
Also, to clarify, context.People is of type DbSet, which implements both IQueryable and IEnumerable. So I 'm not actually sure which .Where method is being called. IntelliSense tells me it is the IQueryable version, but can this be trusted? Is this always the case when working directly with a DbSet of a context?
IEnumerable<Person> people = context.People;
Person person = people.Where(x => x.FirstName == "John");
... will execute the IEnumerable<T>.Where method extension, which accepts a Func<TSource, bool> predicate parameter, forcing the filtering to happen in memory.
In contrast...
IEnumerable<Person> people = context.People.Where(x => x.FirstName == "John");
...will execute the IQueryable<T>.Where method extension, which accepts a Expression<Func<TSource, bool>> predicate parameter. Notice that this is an expression, not a delegate, which allows it to translate the where condition to a database condition.
So it really does make a difference which extension method you invoke.
IQueryable<T> works on expressions. It is effectively a query-builder, accumulating information about a query without doing anything... until the moment you need a value from it, when:
a query is generated from the accumulated Expression, in the target language (e.g. SQL)
the query is executed, usually on the database,
results are converted back to a C# object.
IEnumerable<T> extensions works on pre-compiled functions. When you need a value from it:
C# code in those functions is executed.
It is easy to confuse the two, because:
both have extension functions with similar names,
the lambda syntax is the same for Expressions and Functions - so you cannot tell them apart,
the use of "var" to declare variables removes the datatype (often the only clue as to which interface is being used).
IQueryable<int> a;
IEnumerable<int> b;
int x1 = a.FirstOrDefault(i => i > 10); // Expression passed in
int x2 = b.FirstOrDefault(i => i > 10); // Function passed in
Extension methods with the same name usually do the same thing (because they were written that way) but sometimes they don't.
So the answer is: No, they are not equivalent.

Do interfaces not care about the name of the method when using Lambda expressions?

I guess I am a little confused by a couple of lines of code I have seen.
The first one:
IEnumerable<SignalViewModel> SelectionQuery =
from SignalViewModel svm in AvailableSignalsListView.SelectedItems
orderby AvailableSignalsListView.Items.IndexOf(svm)
select svm;
_GraphViewerViewModel.SelectAvailableSignals(SelectionQuery);
makes sense to me because the orderby defined here:
http://msdn.microsoft.com/en-us/library/bb534966%28v=vs.110%29.aspx
takes a source and a key selector. I am guessing that the query portion
orderby AvailableSignalsListView.Items.IndexOf(svm) creates a lambda expression and calls
Enumerable.OrderBy<TSource, TKey> Method (IEnumerable<TSource>, Func<TSource, TKey>)
with the IEnumerable<TSource> being AvailableSignalsListView.SelectedItems
and the Func<TSource, TKey> being a lambda expression created from the query statement along the lines of
svm => AvailableSignalsListView.Items.IndexOf(svm);
This one makes sense to me though i'm uncertain if my understanding of the details is correct.
The second one,
List<SignalViewModel> mySelectedItems = new List<SignalViewModel>();
//sort version
foreach (SignalViewModel svm in AvailableSignalsListView.SelectedItems)
{
mySelectedItems.Add(svm);
}
mySelectedItems.Sort((x,y) => AvailableSignalsListView.Items.IndexOf(x).CompareTo(AvailableSignalsListView.Items.IndexOf(y)));
doesn't make sense because sort takes an icomparer. I can accept that an icomparer only needs a function as defined by its interface (that takes two items and returns an int). However, how does the computer know what function name to give the delegate behind the scenes? or do interfaces not actually care about the names of functions?
There are several overloads to List.Sort. One that takes an IComparer interface, and one that takes a Comparison delegate. This is using the latter.
If you had a method that only accepted an interface you couldn't pass in a delegate; that wouldn't work.

IQueryable OrderBy with Func<TModel, TValue> : what's happening

With the code given from this question
OrderBy is not translated into SQL when passing a selector function
Func<Table1, string> f = x => x.Name;
var t = db.Table1.OrderBy(f).ToList();
The translated SQL is:
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name]
FROM [dbo].[Table1] AS [Extent1]
OK.
I can understand that the code compiles : IQueryable inherits from IEnumerable, which have an OrderBy method taking a Func<TModel, TValue> as parameter.
I can understand that the ORDER BY clause is not generated in SQL, as we didn't pass an Expression<Func<TModel, TValue>> as the OrderBy parameter (the one for IQueryable)
But what happens behind the scene ? What happens to the "wrong" OrderBy method ? Nothing ? I can't see how and why... Any light in my night ?
Because f is a delegate rather than an expression, the compiler picks the IEnumerable OrderBy extension method instead of the IQueryable one.
This then means that all the results are fetched from the database, because the ordering is then done in memory as if it were Linq to Objects. That is, in-memory, the ordering can only be done by fetching all the records.
Of course, in reality this still doesn't actually happen until you start enumerating the result - which in your case you do straight away because you eager-load the result with your call to ToList().
Update in response to your comment
It seems that your question is as much about the IQueryable/IEnumerable duality being 'dangerous' from the point of view of introducing ambiguity. It really isn't:
t.OrderBy(r => r.Field)
C# sees the lambda as an Expression<> first and foremost so if t is an IQueryable then the IQueryable extension method is selected. It's the same as a variable of string being passed to an overloaded method with a string and object overload - the string version will be used because it's the best representation.
As Jeppe has pointed out, it's actually because the immediate interface is used, before inherited interfaces
t.AsEnumerable().OrderBy(r => r.Field)
C# can't see an IQueryable any more, so treats the lambda as a Func<A, B>, because that's it's next-best representation. (The equivalent of only an object method being available in my string/object analogy before.
And then finally your example:
Func<t, string> f = r => r.Field;
t.OrderBy(f);
There is no possible way that a developer writing this code can expect this to be treated as an expression for a lower-level component to translate to SQL, unless the developer fundamentally doesn't understand the difference between a delegate and an expression. If that's the case, then a little bit of reading up solves the problem.
I don't think it's unreasonable to require a developer to do a little bit of reading before they embark on using a new technology; especially when, in MSDN's defence, this particular subject is covered so well.
I realise now that by adding this edit I've now nullified the comment by #IanNewson below - but I hope it provides a compelling argument that makes sense :)
But what happens behind the scene?
Assuming db.Table1 returns an Table<Table1>, the compiler will:
Check whether Table<T> has an OrderBy method - nope
Check whether any of the base classes or interfaces it implements has an OrderBy method - nope
Start looking at extension methods
It will find both Queryable.OrderBy and Enumerable.OrderBy as extension methods which match the target type, but the Queryable.OrderBy method isn't applicable, so it uses Enumerable.OrderBy instead.
So you can think of it as if the compiler has rewritten your code into:
List<Table1> t = Enumerable.ToList(Enumerable.OrderBy(db.Table1, f));
Now at execution time, Enumerable.OrderBy will iterate over its source (db.Table1) and perform the appropriate ordering based on the key extraction function. (Strictly speaking, it will immediately return an IEnumerable<T> which will iterate over the source when it's asked for the first result.)
The queryable returns all records (hence no WHERE clause in the SQL statement), and then the Func is applied to the objects in the client's memory, through Enumerable.OrderBy. More specifically, the OrderBy call resolves to Enumerable.OrderBy because the parameter is a Func. You can therefore rewrite the statement using static method call syntax, to make it a bit clearer what's going on:
Func<Table1, string> f = x => x.Name;
var t = Enumerable.OrderBy(db.Table1, f).ToList();
The end result is that the sort specified by OrderBy is done by the client process rather than by the database server.
This answer is a kind of comment to Andras Zoltan's answer (but this is too long to fit in the comment format).
Zoltan's answer is interesting and mostly correct, except the phrase C# sees the lambda as an Expression<> first and foremost [...].
C# sees a lambda (and any anonymous function) as equally "close" to a delegate and the Expression<> (expression tree) of that same delegate. According to the C# specification, neither is a "better conversion target".
So consider this code:
class C
{
public void Overloaded(Expression<Func<int, int>> e)
{
Console.WriteLine("expression tree");
}
public void Overloaded(Func<int, int> d)
{
Console.WriteLine("delegate");
}
}
Then:
var c = new C();
c.Overloaded(i => i + 1); // will not compile! "The call is ambiguous ..."
So the reason why it works with IQueryable<> is something else. The method defined by the direct interface type is preferred over the method defined in the base interface.
To illustrate, change the above code to this:
interface IBase
{
void Overloaded(Expression<Func<int, int>> e);
}
interface IDerived : IBase
{
void Overloaded(Func<int, int> d);
}
class C : IDerived
{
public void Overloaded(Expression<Func<int, int>> e)
{
Console.WriteLine("expression tree");
}
public void Overloaded(Func<int, int> d)
{
Console.WriteLine("delegate");
}
}
Then:
IDerived x = new C();
x.Overloaded(i => i + 1); // compiles! At runtime, writes "delegate" to the console
As you see, the member defined in IDerived is chosen, not the one defined in IBase. Note that I reversed the situation (compared to IQueryable<>) so in my example the delegate overload is defined in the most derived interface and is therefore preferred over the expression tree overload.
Note: In the IQueryable<> case the OrderBy methods in question are not ordinary instance methods. Instead, one is an extension method to the derived interface, and the other is an extension method to the base interface. But the explanation is similar.

Significance of AsEnumerable?

var query =
from dt1 in dtStudent.AsEnumerable()
join dt2 in dtMarks.AsEnumerable()
on dt1.Field<int>("StudentID")
equals dt2.Field<int>("StudentID")
select new StudentMark
{
StudentName = dt1.Field<string>("StudentName"),
Mark = dt2.Field<int>("Mark")
};
In the above coding, what is the significance of AsEnumerable? if the AsEnumerable doesn't exist in .NET Framework, then what would be the approach of developers to perform the above the task?
Assuming I'm interpreting it correctly, it's calling DataTableExtensions.AsEnumerable(). Without that (or something similar), you can't use LINQ to Objects as DataTable doesn't implement IEnumerable<T>, only IEnumerable.
Note that an alternative would be to use Cast<DataRow>, but that would be subtly different as that would use the DataTable's GetEnumerator directly within Cast, whereas I believe EnumerableRowCollection<TRow> does slightly more funky things with the data table. It's unlikely to show up any real changes, except possibly a slight performance difference.
The .AsEnumerable() extension is just short-hand for casting something that implements IEnumerable<T> to be IEnumerable<T>
So, if xs is int[], you can call xs.AsEnumerable() instead of (xs as IEnumerable<int>). It uses type inference to avoid needing to explicitly keying the type of xs.
Here's the code extracted by Reflector.NET:
public static IEnumerable<TSource> AsEnumerable<TSource>(
this IEnumerable<TSource> source)
{
return source;
}
But in this case I think I have to agree with Jon. It's probably from the System.Data.DataSetExtensions assembly.

Using Extension methods versus lambda expression in c#

Suppose I have an extension method
public static IEnumerable<Product> Filter(
this IEnumerable<Product> productEnum,
Func<Product, bool> selectorParam)
{
return productEnum.Where(selectorParam);
}
which I call like so
Func<Product, bool> languageFilter = prod => prod.Language == lang;
Which if im not misaken is functionally the same as
var products = Products.Where(q => q.Language == parameter);
I'm trying to understand when one might utilize an extension method as per the 1st sample, and when to use the linq syntax.
I think you are confusing some terminology. The Filter method you show is an extension method (indicated as such by the this keyword in the parameter list. What you are terming as "linq syntax" is actually a lambda expression.
All of the LINQ methods are implemented as extension methods and support two "styles" of calling:
Actually call the extension method directly as if they were part of the type being extended. This is what you show when calling it as productEnum.Where(selectorParam).
Using a more SQL-like syntax, called LINQ query syntax. Keep in mind that this SQL-like syntax is translated by the compiler to actually call the extension methods.
When you define Func<Product, bool> languageFilter = prod => prod.Language == lang;, you are actually defining a lambda expression and assigning it to a variable (languageFilter) of type Func<Product, bool>. The Products.Where(q => q.Language == parameter); statement is exactly the same except that rather than capturing the lambda expression in a variable you simply pass it to the extension method.
For your example, to get the same result using the LINQ query syntax you would write it similar to
from p in Products
where p.Language == parameter
(assuming that parameter is defined elsewhere)
I think if there is already an extension method in the framework to do what you want, use that. The 'Where' method is also an extension method, just not one you wrote. My rationale is that 'those clever Microsoft chaps have probably done this better than I ever would'.
Internally, linq syntax is broken into an extension method, so there is functionally no difference.
In your case where you have a Filter extension method, it might not make much sense to use the first form.(which i assume is incomplete in your question, by accident). However, let's assume there's some commonly used logic you need to perform in your Filter method which you would not want to repeat over and over in every instance of a where clause. In that case, it makes sense to build a custom extension method so you can reuse that logic.
For instance, let's assume we only work with products that have not expired(assuming your Product object has an isExpired property). Since, you're likely to be filtering on these unexpired products further with several selectorParam values, you can just use:
public static IEnumerable<Product> Filter(
this IEnumerable<Product> productEnum,
Func<Product, bool> selectorParam)
{
return productEnum.Where(x => !x.IsExpired).Where(selectorParam);
}
So instead of calling products.Where(x => !x.IsExpired).Where(q => q.Language == parameter)
or products.Where(x => !x.IsExpired).Where(q => q.Price > parameter)
you could just use :
products.Filter(q => q.Language == parameter) and products.Filter(q => q.Price > parameter) respectively.

Categories