Here is my query, using EntityFramework 6.0
var x = context.Student
.Include(d => d.Class.Select(di => di.Teachers).Select(i => i.Subjects))
.Include(d => d.Class.Select(di => di.Teachers).Select(di => di.Marks))
.firstOrDefault();
Entities Subject and Class are childern of Teachers entity. How to include both the child entities in one query?
When the query is executed, does the Teachers entity will be loaded twice?
As the 'class' table is included twice, when the SQL is generated does it joins the 'class' table 2 times?
Are you using EF6 or EF Core? On EF Core you can use ThenInclude to load deeper level entities. Like (from MS Docs):
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author)
.ThenInclude(author => author.Photo)
.Include(blog => blog.Owner)
.ThenInclude(owner => owner.Photo)
.ToList();
}
Related
I have a question about Include function in EF6.
I have multiple entities linked to a single entity for example:
SonA, SonB, SonC are all linked to FatherABC entity.
FatherABC has linked entities of his own: BrotherA, BrotherB, BrotherC
Now if I use include like this :
Son son = context.Sons.Where(x => ids.Contains(x => x.id))
.Include(x => x.Father)
.Include(x => x.Father.Brother)
.FirstOrDefault();
Will the include Father/Father.Brother work a single time for all of the entities? since it's the same entity?
Or will it query the data for each of the son entities?
Son son = context.Sons.Where(x => ids.Contains(x => x.id))
.Include(x => x.Father)
.ThenInclude(f => f.Brother)
.FirstOrDefault();
This should work
I am trying to find an equivalent Linq Query to run the below code in SQL Database using EF Core.
var result = Logs.Where(x => x.ProjectCode.Equals(projectCode))
.OrderByDescending(x => x.SubmittedDate).DistinctBy(y => new { y.GeographyCode, y.DataSetId })
The DistinctBy operation is creating an issue while translating query string from context. I am not sure how to write an equivalent LINQ operation that is compatible with EF Core which takes 2 distinct properties.
Is there a way to do this? I want to run this query on the SQL server end.
try GroupBy
var result = Logs.Where(x => x.ProjectCode.Equals(projectCode))
.OrderByDescending(x => x.SubmittedDate)
.GroupBy(y => new { y.GeographyCode, y.DataSetId })
.Select(g => g.First())
.ToList();
I am trying the following Linq with LinqPad connecting to SQL Server with EF Core:
MyTable.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.SelectMany(x => x)
I get this error:
The LINQ expression 'x => x' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explic...
However, this works:
MyTable.AsEnumerable()
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.SelectMany(x => x)
I was under the impression that EF Core should be able to translate such an expression.
Am I doing anything wrong?
That exception message is an EF Core message, not EF6.
In EF 6 your expression should work, though with something like a ToList() on the end. I suspect the error you are encountering is that you may be trying to do something more prior to materializing the collection, and that is conflicting with the group by SelectMany evaluation.
For instance, something like this EF might take exception to:
var results = MyTable
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.SelectMany(x => x)
.Select(x => new ViewModel { Id = x.Id, Name = x.Name} )
.ToList();
where something like this should work:
var results = MyTable
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.SelectMany(x => x.Select(y => new ViewModel { Id = y.Id, Name = y.Name} ))
.ToList();
You don't want to use:
MyTable.AsEnumerable(). ...
As this is materializing your entire table into memory, which might be ok if the table is guaranteed to remain relatively small, but if the production system grows significantly it forms a cascading performance decline over time.
Edit: Did a bit of digging, credit to this post as it does look like another limitation in EF Core's parser. (No idea how something that works in EF6 cannot be successfully integrated into EF Core... Reinventing wheels I guess)
This should work:
var results = MyTable
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.Select(x => x.Key)
.SelectMany(x => _context.MyTable.Where(y => y.Key == x))
.ToList();
So for example where I had a Parent and Child table where I wanted to group by ParentId, take the top 5 parents and select all of their children:
var results = context.Children
.GroupBy(x => x.ParentId)
.OrderBy(x => x.Key) // ParentId
.Take(5)
.Select(x => x.Key) // Select the top 5 parent ID
.SelectMany(x => context.Children.Where(c => c.ParentId == x)).ToList();
EF pieces this back together by doing a SelectMany back on the DbSet against the selected group IDs.
Credit to the discussions here: How to select top N rows for each group in a Entity Framework GroupBy with EF 3.1
Edit 2: The more I look at this, the more hacky it feels. Another alternative would be to look at breaking it up into two simpler queries:
var keys = MyTable.OrderBy(x => x.SomeField)
.Select(x => x.SomeField)
.Take(5)
.ToList();
var results = MyTable.Where(x => keys.Contains(x.SomeField))
.ToList();
I think that translates your original example, but the gist is to select the applicable ID/Discriminating keys first, then query for the desired data using those keys. So in the case of my All children from the first 5 parents that have children:
var parentIds = context.Children
.Select(x => x.ParentId)
.OrderBy(x => x)
.Take(5)
.ToList();
var children = context.Children
.Where(x => parentIds.Contains(x.ParentId))
.ToList();
EF Core has limitation for such query, which is fixed in EF Core 6. This is SQL limitation and there is no direct translation to SQL for such GroupBy.
EF Core 6 is creating the following query when translating this GroupBy.
var results = var results = _context.MyTable
.Select(x => new { x.SomeField })
.Distinct()
.OrderBy(x => x.SomeField)
.Take(5)
.SelectMany(x => _context.MyTable.Where(y => y.SomeField == x.SomeField))
.ToList();
It is not most optimal query for such task, because in SQL it can be expressed by Window Function ROW_NUMBER() with PARTITION on SomeField and additional JOIN can be omitted.
Also check this function, which makes such query automatically.
_context.MyTable.TakeDistinct(5, x => x.SomeField);
I have linq query like this in EF Core 2.0, It work as it is, but when I upgrade to EF Core 3.0 it always timeout. I found the issue in query = query.Where(x => x.Questions);.
My Question is i would like to return the course with filter questions like only Take(10) or with .Where condition that only display certain range not all questions.
var query = _courseRepository.Table;
query = query.Where(x => x.Id == id);
query = query.Include(x => x.Questions);
query = query.Include(x => x.CourseYear);
query = query.Include(x => x.CourseSubject);
query = query.Include(x => x.Instructors).ThenInclude(y => y.User);
query = query.Include(x => x.Instructors).ThenInclude(y => y.Course);
query = query.Include(x => x.Instructors).ThenInclude(y => y.CourseClass);
query = query.Include(x => x.CourseSections);
query = query.Include(x => x.CourseSections).ThenInclude(y => y.Lessons);
query = query.Include(x => x.CourseClasses);
query = query.Include(x => x.UserCourses).ThenInclude(y => y.User);
var result = query.FirstOrDefault();
EFCore 3.0 changed the query(ies) generated by using .Include() and you are experiencing the Cartesian Explosion Problem;
Specifically there is the following Red Caution in the Docs now:
Caution
Since version 3.0.0, each Include will cause an additional JOIN to be
added to SQL queries produced by relational providers, whereas
previous versions generated additional SQL queries. This can
significantly change the performance of your queries, for better or
worse. In particular, LINQ queries with an exceedingly high number of
Include operators may need to be broken down into multiple separate
LINQ queries in order to avoid the cartesian explosion problem.
The solution is to execute multiple queries now per the docs.
Its super unfortunate loading entity graphs, common to highly normalized data, is so un-performant but this is its current state with EF.
See: Loading Related Data and scroll until you see red.
var query = _courseRepository.Table
.Include(x => x.Questions)
.Include(x => x.CourseClasses)
.Include(x => x.CourseYear)
.Include(x => x.CourseSubject);
var course = await query.FirstOrDefaultAsync(x => x.Id == id);
query.Include(x => x.Instructors).ThenInclude(y => y.User).SelectMany(a => a.Instructors).Load();
query.Include(x => x.Instructors).ThenInclude(y => y.Course).SelectMany(a => a.Instructors).Load();
query.Include(x => x.Instructors).ThenInclude(y => y.CourseClass).SelectMany(a => a.Instructors).Load();
query.Include(x => x.CourseSections).ThenInclude(y => y.Lessons).SelectMany(a => a.CourseSections).Load();
query.Include(x => x.UserCourses).ThenInclude(y => y.User).SelectMany(a => a.UserCourses).Load();
I have to load an entity from the database and I need to eagerly load into that entity almost all the relations from the database. I tried using Include but without success. Here is the code:
var thingy = _ctx.MASTERANDCOMMANDER
.Include(x => x.RED)
.Include(x => x.RED.Select(y => y.RED_ONE))
//.Include(x => x.RED.Select(y => y.RED_TWO))
.Include(x => x.GREEN)
.Include(x => x.GREEN.Select(y => y.GREEN_ONE))
.Include(x => x.GREEN.Select(y => y.GREEN_ONE.Select(z => z.GREEN_ONE_BIG)))
//.Include(x => x.GREEN.Select(y => y.GREEN_TWO))
//.Include(x => x.GREEN.Select(y => y.GREEN_THREE))
.SingleOrDefault(x => x.ID == "someId");
If I uncomment any of those includes, the app throws:
System.Exception: Oracle 11.2.0.2.0 doesn't support APPLY
Using EntityFramework 6 and Oracle 11.2.0.2.0.
I cannot upgrade EF nor Oracle.
How can I load the relations from GREEN_TWO, etc. into thingy?
Edit: All relations shown are one to many from left to right. Examples:
RED (1 to *) RED_ONE
GREEN_ONE (1 to *) GREEN_ONE_BIG
You can always use Join instead of Include, e. g.:
var thingy = _ctx.MASTERANDCOMMANDER
.Join(RED, x => x.MASTERANDCOMMANDERID, x => REDID, (m, r) => m)...etc...
and so on, where you need to get RED from your database as another single entity.
maybe using .ThenInclude() would help
var thingy = _ctx.MASTERANDCOMMANDER
.Include(x => x.RED)
.ThenInclude(red => red.RED_ONE)
.Include(x => x.GREEN)
.ThenInclude(green => green.GREEN_ONE)
.ThenInclude(greenOne => greenOne.GREEN_ONE_BIG)
.Where(x => x.ID == "someId").SingleOrDefault();