Load EF entity with sibling includes - c#

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();

Related

Use multiple include and then include in EF query C#

I tried this code:
var result = _repository.Entity
.Include(x => x.table1)
.Include(x => x.table2).ThenInclude(x => x.table3).ThenInclude(x => x.table4)
.Where(x => x.table1.Id == 10)
I want to achieve like below which is not working:
var result = _repository.Entity
.Include(x => x.table1).select(new table1{..})
.Include(x => x.table2).ThenInclude(x => x.table3).ThenInclude(x => x.table4)
.Where(x => x.table1.Id == 10)
In this query, I want to use select on table1 i.e. to select on few columns say id, name.
I am trying but I use select right after the .Include(x => x.table1).select(....) then I am unable to use .Include for other tables.
I am not sure how to achieve this with join conditions; I tried but not able to achieve this, a small idea to resolve this will be helpful to proceed further.

EF Core 3.0 .Include does not work as expected and Super Slow

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();

EF core, Any could not be translated and will be evaluated locally

I have procedure which returns me entity's ids which I need.
(I decide to create this procedure, because entities which should be returned to the end user, are filtered by related entities, but EF Core does not support filtering by related entities).
Then I want to use this ids to get entities I need witch theirs related entities.
I'm using the Any operator. In my opinion it should generate query like this: WHERE id IN(1,2,3,4....)` but it seems it does not work like I want.
Instead, it returns warning with the information that the:
Any clause could not be translated and will be evaluated locally
How I could fix it?
My code below:
var assocsIds = await _context.Assoc.AsNoTracking()
.FromSql($"exec {SqlProcedures.GetAssocsForIndexProc} {query.IndexMviId}, {query.FilterByGroupId}")
.ToListAsync()
var productAssocs = await _context.Assoc
.Where(x => assocsIds.Any(z => z.Id == x.Id))
.Include(x => x.Attribute)
.ThenInclude(x => x.Translation)
.Include(x => x.Option)
.ThenInclude(x => x.Translation)
.Include(x => x.Mvi)
.ThenInclude(x => x.Translation)
.AsNoTracking()
.ToListAsync()
;
Can you first select "Id"s from assocsIds into another variable and then try the following?
var productAssocs = await _context.Assoc
.Where(x => yourIdsList.Contains(x.Id))
.Include(x => x.Attribute)
.ThenInclude(x => x.Translation)
.Include(x => x.Option)
.ThenInclude(x => x.Translation)
.Include(x => x.Mvi)
.ThenInclude(x => x.Translation)
.AsNoTracking()
.ToListAsync();

EF Core Including multiple levels issue

With EF 6, I was querying like this and it was working nice.
IQueryable<Student> query = _testHelper.buildQuerty(id, userId)
.Include(x => x.Class)
.Include(x => x.Subjects)
.Include(x => x.Subjects.Select(y => y.Category));
Problem:
The same does not work in EF Core 2.0.
Error
System.ArgumentException occurred HResult=0x80070057 Message=The
property expression 'Subjects => {from Subjects y in Subjects select
[y].Category}' is not valid. The expression should represent a property
access: 't => t.MyProperty'. For more information on including
related data, see http://go.microsoft.com/fwlink/?LinkID=746393.
Opened up link, and refactored like this but it still not working and gives same error.
List<Student> query = _testHelper.buildQuerty(id, userId)
.Include(x => x.Class)
.Include(x => x.Subjects)
.ThenInclude(Subjects => Subjects.Select(y => y.Category)).tolist();
Where is the problem?
You're using the last chain of ThenInclude wrongly. You should use it like the code below.
List<Student> query = _testHelper.buildQuerty(id, userId)
.Include(x => x.Class)
.Include(x => x.Subjects)
.ThenInclude(subject => subject.Category);
With this ThenInclude extension method, you're dealing with an instance of Subject because of the last of use of Include which deal with a collection of that type.

Linq - where inside include

I know that this won't work as written, but I'm struggling to see the right answer, and this non-functional code hopefully illustrates what I'm trying to achieve:
var defaults = _cilQueryContext.DefaultCharges
.Where(dc => dc.ChargingSchedule_RowId == cs.RowId);
List<DevelopmentType> devTypes =
defaults.Select(dc => dc.DevelopmentType)
.Include(d => d.DefaultCharges)
.Include(d => d.OverrideCharges.Where(oc => oc.ChargingSchedule_RowId == cs.RowId))
.Include(d => d.OverrideCharges.Select(o => o.Zone))
.ToList();
Essentially, I had presumed this required a join, but seeing as I'm trying to select a parent object containing two related types of children, I can't see what would go in the join's "select new" clause.
As far as I am aware Include does not support this type of sub-querying. Your best option is to use projection e.g.
List<DevelopmentType> devTypes =
defaults.Include(x => x.DefaultCharges)
.Include(x => x.OverrideCharges)
.Select(x => new {
DevType = x.DevelopmentType,
Zones = x.OverrideCharges.Where(oc => oc.ChargingSchedule_RowId == cs.RowId)
.Select(oc => oc.Zone).ToList()
})
.Select(x => x.DevType)
.ToList();

Categories