Difference between cast and as inside a select in LINQ - c#

This code throws exception:
var query = services
.SomeQuery(bar).select(x => (Foo)x)
.Where(x.PropertyOfFoo == FooState.SomeState);
var result = query.ToList();
The exception:
Unable to cast the type...
LINQ to Entities only supports casting EDM primitive or enumeration types.
This code works:
var query = services
.SomeQuery(bar).select(x => x as Foo)
.Where(x.PropertyOfFoo == FooState.SomeState);
var result = query.ToList();
Why does as allow the conversion and cast does not?
I understand that as will return null and cast would throw an exception if either call fails. Okay. But when I run this code:
var query = services
.SomeQuery(bar);
var result = query.ToList();
I get a much larger query result. Why?

LINQ to Entities is not the same as LINQ to Objects. While LINQ to Objects functions can take any matching delegate and blindly invoke it as normal C# code, LINQ to Entities treats your lambdas as expression trees because it needs to understand the semantics of those lambdas (not just their signature) and transform them to an equivalent query for your EF backend. Naturally, this means that LINQ to Entities can't handle all operations that LINQ to Objects can.
Now, as you have said, one difference between casting and using as is that casting throws an exception on failure and as returns null. But there is an even more important difference between the two: a cast will apply any potential custom explicit conversions, while as will simply attempt to reinterpret the reference as something else, ignoring any potential conversions.
As you understand, a cast is much more complicated than as, because a cast may invoke a custom method (the explicit operator) that's not easily resolvable by the LINQ provider. It's likely that the provider is simply unable to examine the code of the potential custom conversion (I don't know enough about the limitations of expression trees), let alone translate it for the underlying source. Thus, LINQ to Entities chooses to allow only as and the simplest cast cases (basically, it allows the cases where the conversion logic was known ahead of time and can't possibly be custom user code).

There's an important difference between the two statements that shows that more than anything (like CLR rules) Entity Framework is deeply involved here.
x as Foo is translated into SQL. EF can do that because it knows it will always return a result, either a Foo or null. The generated SQL is monstrous by the way, but it does the job.
(Foo)x is not translated into SQL. EF knows that there is no way to create Foo objects for all x's, as cast semantics demand, and it throws an exception.
Note that EF will accept foos.Select(f => (Bar)f), because it's always possible to create a base type from a subtype. The actual cast is done after the SQL result is received, it doesn't affect the SQL itself.
It will also accept bars.OfType<Foo>().Select(x => (Foo)x) (althought this is fairly useless).
So the error message...
LINQ to Entities only supports casting EDM primitive or enumeration types.
...isn't entirely true. EF does accept casts when they're doable. So inside EF's query translator there's just a bunch of logic to decide whether or not it's worth the effort to generate a SQL statement.

It's a difference in how direct cast works vs. how the as operator works. Direct cast isn't available because you aren't using a value type - it only works for primitives.
Now, your lambda is trying to both select and project - you could break that into two operations, so:
var result = services.SomeQuery(bar).select(x => new Foo() {
SomeProperty = x.SomeProperty,
SomeOtherProperty = x.SomeOtherProperty,
... }).ToList()
As to the greater number of results: you're missing a where clause in there.

Related

How does the compiler/runtime determine a lambda expression's type?

I was wondering how the the compiler/runtime determines a lambda expression's type?
For example, the following System.Linq Select extension method (not select query)
//var recordIds = new List<int>(records.Select(r => r?.RecordId ?? 0));
//var recordIds = new List<int>(records.Where(r => r != null).Select(r => r.RecordId));
var recordIds = new List<int>(records.Select(r => r.RecordId));
is defined as
Enumerable.Select<TSource, TResult> Method (IEnumerable<TSource>, Func<TSource, TResult>)
and so takes the lambda r => r.RecordId as a Func<TSource, TResult>.
How is the lambda's type determined, and once it is, is it simply cast to that type?
I was wondering how the the compiler/runtime determines a lambda expression's type?
It is rather complicated. Implementing this feature was the "long pole" for the version of Visual Studio that shipped C# 3 -- so every day that I was over schedule on this was a day that VS would slip! -- and the feature has only gotten more complicated with the introduction of covariance and contravariance in C# 4.
As others have noted, consult the specification for exact details. You might also read the various articles I've written about it over the years.
I can give you a quick overview though. Suppose we have
records.Select(r => r.RecordId)
where records is of type IEnumerable<Record> and RecordId is of type int.
The first question is "does IEnumerable<Record> have any applicable method called Select? No, it does not. We therefore go to the extension method round.
The second question then is: "is there any static type with an accessible extension method that is applicable to this call?"
SomeType.Select(records, r => r.RecordId)
Let's suppose that Enumerable is the only such type. It has two versions of Select, and one of them takes a lambda that takes two parameters. We can automatically discard that one. That leaves us with, as you note:
static IEnumerable<R> Select<A, R>(IEnumerable<A>, Func<A, R>)
Third question: Can we deduce the type arguments corresponding to type parameters A and R?
In the first round of type inference we consider all the non-lambda arguments. We only have one. We deduce that A could be Record. However, IEnumerable<T> is covariant, so we make a note that it could be a type more general than Record as well. It cannot be a type that is more specific than Record though.
Now we ask "are we done?" No. We still don't know R.
"Are there any inferences left to make?" Yes. We haven't checked the lambda yet.
"Are there any contradictions or additional facts to know about A?" Nope.
We therefore "fix" A to Record and move on. What do we know so far? We have:
static IEnumerable<R> Select<Record, R>(IEnumerable<Record>, Func<Record, R>)
We then say OK, the argument must be (Record r) => r.RecordId. Can we infer the return type of this lambda knowing that? Plainly yes, it is int. So we put a note on R saying that it could be int.
Are we done? Yes. Is there anything else we can make a deduction about? No. Did we infer all the type parameters? Yes. So we "fix" R to int, and we're done.
Now we do a final round that checks to make sure that Select<Record, int> does not produce any errors; for example, if Select had a generic constraint that was violated by <Record, int> we would reject it at this point.
We've deduced that records.Select(r=>r.RecordId) means the same thing as Enumerable.Select<Record, int>(records, (Record r) => { return (int)r.RecordId; } ) and that's a legal call to that method, so we're done.
Things get rather more complicated when you introduce multiple bounds. See if you can figure out how something like a Join works where there are four type parameters to infer.
I think the best place to look for such information is the language spec:
Section 7.15
An anonymous function is an expression that represents an “in-line”
method definition. An anonymous function does not have a value or type
in and of itself, but is convertible to a compatible delegate or
expression tree type. The evaluation of an anonymous function
conversion depends on the target type of the conversion: If it is a
delegate type, the conversion evaluates to a delegate value
referencing the method which the anonymous function defines. If it is
an expression tree type, the conversion evaluates to an expression
tree which represents the structure of the method as an object
structure.
The above explains the nature of lambda expressions, basically that they have no types by themselves, unlike say, an int literal 5. Another point to note here is that the lambda expression is not casted to the delegate type like you said. It is evaluated, just like how 3 + 5 is evaluated to be of int type.
Exactly how these types are figured out (type inference) is described in section 7.5.2.
...assume that the generic method has the following signature:
Tr M<X1…Xn>(T1
x1 … Tm xm)
With a method call of the form M(E1 …Em) the
task of type inference is to find unique type arguments
S1…Sn for each of the type parameters
X1…Xn so that the call
M1…Sn>(E1…Em)becomes
valid.
The whole algorithm is quite well documented but it's kind of long to post it here. So here's a link to download the language spec.
https://msdn.microsoft.com/en-us/library/ms228593(v=vs.120).aspx

Cast an Interface and IQueryable<Interface> to its concrete implementation [duplicate]

I know about covariance, and I know that in general it will not be possible in C# until v4.0.
However I am wondering about a specific case. Is there some way of getting converting IQueryable<Derived> to IQueryable<Base> by somehow creating a wrapper class that does not actually perform a query, but can actually "pass through" a .Where<>() call?
My use case is that I am trying to deal with a database schema that has many similar tables. Most of the fields are in common, and many of the common fields need to be queried on each table. I'm using LinqToSql. I was hoping to avoid duplicating all the queries for each table.
Is the following what you are looking for?
var results = queryable.OfType<Base>.Where(...);
The OfType method will gather up anything that is of the specified type, and if all items in the collection are either of type Base, or derived from type base, they should qualify. In the subsequent where, all items would be of type Base.
The following will also work, altough it is less pretty:
var results = queryable.Select(derived => (Base)derived).Where(...);

Understanding two methods with LINQ and lambda

I have a question, my friend and I are doing code, and he did two methods that I don't exactly understands.
public static List<Borrow> GetDistinctBorrows(List<Borrow> list)
{
var Result = (from bor in list group bor by new { bor.BookAccessor, bor.ReaderAccessor } into dist select dist.First()).ToList();
return Result;
}
and a second one
public static List<Borrow> GetDistinctBorrows(List<Borrow> list)
{
var Result = list.GroupBy(x => new { x.ReaderAccessor, x.BookAccessor }).Select(y => y.First()).ToList();
return Result;
}
Those methods have the same functionality, but one are written with LINQ, and a second one with lambda expressions.
Can someone explain to me, how they work (especially the fragment with 'new' word)?
The part with new word is how you define instances on Anonymous Types.
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.
You create anonymous types by using the new operator together with an object initializer. For more information about object initializers, see Object and Collection Initializers (C# Programming Guide).
As a side note, your queries are equivalent, because compiler will transform the first one onto the second one as part of compilation process. Read more about that on MSDN: Query Syntax and Method Syntax in LINQ (C#)
Most queries in the introductory Language Integrated Query (LINQ) documentation are written by using the LINQ declarative query syntax. However, the query syntax must be translated into method calls for the .NET common language runtime (CLR) when the code is compiled. These method calls invoke the standard query operators, which have names such as Where, Select, GroupBy, Join, Max, and Average. You can call them directly by using method syntax instead of query syntax.
The functions gets a list of distinct items from the input list, where ReaderAccessor and BookAccessor determine equality. Duplicated items from the input list is discarded.
They work by grouping by a new anonymous object defined by the two properties (this is where the new keyword is used), creates an alias dist and then taking the first one, essentially discarding the rest.

Converting from Expression<Func<TypeIn, TypeOut1>> to Expression<Func<TypeIn, TypeOut2>>

I could use some help with expression conversion.
I have a method on a class which looks like the following:
protected IQueryOver<TEntity, TEntity> OrderQuery<TOrderBy>(
Expression<Func<TEntity, TOrderBy>> orderBy)
{
return session.QueryOver<TEntity>().OrderBy(orderBy).Asc;
}
This is a generic query for a repository class. I want to keep things generic so I specified the TOrderBy parameter so that the type of the property doesn't matter. However, this implementation example is using NHibernate and I'm trying to do the following:
var query = session.QueryOver<TEntity>().OrderBy(orderBy).Asc;
However, ther OrderBy method takes a parameter of Expression> and therefore I get a compile error as there is no guarantee that TOrderBy would be an object.
Is there a way of doing this conversion or should I just stick with using object rather than TOrderBy? If I stick with object, do I not lose the ability to order by ValueTypes (e.g. DateTime)?
Thanks for any help/suggestions.
EDIT: I should mention, I have kept this generic as I will be writing implementations for nhibernate and entity framework. There isnt an issue with this in EF as it uses the normal Linq OrderBy method. It is just in the Nhibernate implementation I'm having this problem
If you are using LINQ with EF, why not use LINQ with NHibernate too instead of QueryOver?

Sum() causes exception instead of returning 0 when no rows

I have this code (ok, I don't, but something similar :p)
var dogs = Dogs.Select(ø => new Row
{
Name = ø.Name,
WeightOfNiceCats = ø.Owner
.Cats
.Where(æ => !æ.Annoying)
.Sum(æ => æ.Weight),
});
Here I go through all dogs and sum up the weight (into a non-nullable decimal) of all not-annoying cats which has the same owner as the dog. Of course, pretty much all cats are annoying, so I get this error:
The null value cannot be assigned to a member with type System.Decimal which is a non-nullable value type.
None of the fields or foreign keys used can be null. So the error happens when the Where clause returns no cats, which it often does. But how can I solve this? I want it to return 0 when that happens. Tried with a DefaultIfEmpty() after the Where clause, but then I get this error:
Object reference not set to an instance of an object.
Which I guess is understandable. I tried to add a ?? after the Sum, but then it wont compile because of this error:
Operator '??' cannot be applied to operands of type 'decimal' and 'decimal'
Which also makes sense of course. So what can I do? Would be nice if the Sum thing just returned 0 when there was nothing to sum. Or a SumOrZero statement of some sort. Would it be difficult to make a SumOrZero method that worked with Linq2SQL?
This is what I ended up with for now:
.Sum(æ => (decimal?) æ.Weight) ?? 0.0M,
This works like a charm.
I would still prefer to have a SumOrZero I could use, which would work exactly like the regular Sum except it would never return null for any reason. Like the others have noted, this would be pretty easy to make for IEnumerable but a bit more icky to create for IQueryable so it would work with Linq2SQL, etc. So I will just leave it at that for now. Although if someone is bored one day and do write a SumOrZero for IQueryable which works with Linq2SQL for all the numeric types, please do let me know :D
In LINQ to Objects it would be easy. With LINQ to SQL it will be harder. You could write your own extension method which called Queryable.Sum with an expression built up from the normal one, with a cast to the nullable type. I suspect you'd need to do the ?? 0m in the calling code though. In other words, you could do:
.SumOrNull(æ => æ.Weight) ?? 0M,
Where the signature for .SumOrNull would be:
public static decimal? SumOrNull<TSource, decimal>(this IQueryable<TSource>,
Func<TSource,decimal> projection)
You could basically write that for all the value types supported in Queryable. You could write it generically, and call the appropriate method in Queryable using reflection, but that would be icky too.
I think you're best off with what you've got, to be honest.
The trick you've already given (.Sum(æ => (decimal?) æ.Weight) ?? 0.0M) is about the best I can think of for this scenario when it executes as a query at the database. A bit annoying, but there are worse things...
Unlike LINQ-to-Objects, you can't just add your own extension method, as it needs to be mapped by the underlying provider.
You want to use DefaultIfEmpty, which will return an IEnumberable with a single element of 0, and that will be semantically the same as you require.
As you have a nullable decimal, you will probably have to use the 2nd version of the method taking 2 parameters.

Categories

Resources