-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query: The wrong type is being selected when an extension method is used in a subquery #6383
Comments
This is still broken in the current bits. Full repro: class Program
{
static void Main(string[] args)
{
using (var ctx = new MyContext())
{
ctx.Database.EnsureDeleted();
ctx.Database.EnsureCreated();
var goodAlbums2 = ctx.Albums
.Where(a => a.Songs.HighestRated().Order <= 3)
.ToList();
}
}
}
public static class Ext
{
public static Song HighestRated(this IEnumerable<Song> songs)
{
return songs.OrderByDescending(s => s.Rating).First();
}
}
public class MyContext : DbContext
{
public DbSet<Song> Songs { get; set; }
public DbSet<Album> Albums { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=.;Database=Repro6363;Trusted_Connection=True;MultipleActiveResultSets=True");
}
}
public class Song
{
public int Id { get; set; }
public int Order { get; set; }
public int Rating { get; set; }
public Album Album { get; set; }
}
public class Album
{
public int Id { get; set; }
public List<Song> Songs { get; set; }
} |
It's worth pointing out, that even when this is fixed, using a helper method like this to DRY the queries is not recommended. We are unable to translate such method, so it will be evaluated on the client, leading to inefficient N+1 queries (querying for list of Albums and then issuing a query for each Album, rather than getting all the information in a single query) |
…hod is used in a subquery Problem was that when translating collection navigation outside projection we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
…hod is used in a subquery Problem was that when translating collection navigation outside projection and AdditionalFromClause we assumed it's always going to be wrapped in a subquery. This is the case for the most part because in order to be useful inside a query, collection needs to have it's cardinality reduced to single element using a result operator (Count, Any, FirstOrDefault etc), which forces subquery on the collection. However it is also possible to use client method, which takes collection and returns single element. For this case, subquery won't be generated and we were unable to translate such query. Fix is to inject subqueries where needed, using same mechanism we use in case of projection. Client method forces materialization on the collection, so it's safe to use.
fixed in dd15830 |
The issue
I have a somewhat complicated expression in a subquery, which I'd like to simplify since I use it a lot, so I defined an extension method on
IEnumerable<MyModelType>
to make it clearer what's happening in the queries. When I try to run the code with the full expression in the subquery, it works, but when I use the extension method, it doesn't.Steps to reproduce
I have the following, somewhat contrived example (similar to the MusicStore example):
In my code, I have this query, which works as expected (gets a list of albums with a song where the highest rated song on the album is in the top three songs).
This works as expected and generates the following SQL:
However, I want to simplify getting the highest rated song in the subquery using the following extension method:
So then when I do this query,
I get this SQL
And then I get this error because the fields for songs (from the subquery) are selected from the database instead of the fields for albums, which is the type the result should be:
Further technical details
EF Core version: 1.0.0
Operating system: macOS 10.11.6
Visual Studio version: (e.g. VS 2013 or n/a) VS Code 1.4.0
Other details about my project setup:
I'm using SQLite as the datastore, but I've also seen this happen using SQL Server.
The text was updated successfully, but these errors were encountered: