This question already has an answer here:
EF Core Include on multiple sub-level collections
(1 answer)
Closed 3 years ago.
I am trying to query an entity with multiple levels of collections, and multiple collections at a single level. I'm using Include() and ThenInclude(), but not having much success. The examples I find don't have multiple collections on the same level and I haven't had any luck applying the technique to my use case.
This is a simplified illustration of my entities. Those with the [] are collections:
Home
Areas[]
Area
Name
Categories[]
Name
Recommendations[]
Subcategories[]
Name
Recommendations[]
Area
Name
Categories[]
Name
Recommendations[]
Subcategories[]
Name
Recommendations[]
I've gotten this far:
result = Home
.Include(x => x.Areas)
.ThenInclude(a => a.Categories)
.ThenInclude(c => c.Subcategories)
.ThenInclude(s => s.Recommendations)
However, this misses the Categories[].Recommendations[] collection. It's because there are two collections at the same level (Recommendations[] and Subcategories[]).
Any suggestions for a way to structure this query so I can get the desired result?
Thanks.
You have to call Include for each level:
result = Home
.Include(x => x.Areas)
.ThenInclude(a => a.Categories)
.ThenInclude(c => c.Subcategories)
.ThenInclude(s => s.Recommendations)
.Include(x => x.Areas)
.ThenInclude(a => a.Recommendations)
You have to write your query as follows:
result = Home
.Include(x => x.Areas)
.ThenInclude(a => a.Categories)
.ThenInclude(s => s.Recommendations)
.Include(x => x.Areas)
.ThenInclude(c => c.Subcategories)
Related
I am loading a customer and its related entities using the following (this is .NET Core 3.1 and Entity Framework Core).
var customer = loyaltyContext.Customer
.Include(c => c.ContactInformation)
.Include(c => c.Address)
.Include(c => c.MarketingPreferences)
.Include(c => c.ContentTypePreferences)
.Include(c => c.ExternalCards)
.Where(c => c.CustomerInternalId == customerInternalId).First();
However, a customer can have more than one ExternalCard, but only one card will be 'ACTIVE', so in pseudo code, what I'd really like to do is:
var customer = loyaltyContext.Customer
.Include(c => c.ContactInformation)
.Include(c => c.Address)
.Include(c => c.MarketingPreferences)
.Include(c => c.ContentTypePreferences)
.Include(c => c.ExternalCards WHERE CardStatus == "ACTIVE")
.Where(c => c.CustomerInternalId == customerInternalId).First();
So I don't return the last 10 cards the customer had (but which are now inactive). Is this possible in any way using EF Core? I can't seem to find the right syntax for this. At least not without having to create additional queries (whereas I'd rather just bring back less data to begin with).
ExternalCards is an ICollection< ExternalCards > as one customer can have many cards.
Filtering include option is not available in EF Core version <= 3.1. It's a new feature in EF Core 5.0. Here it is for EF Core 5.0 : Filtered Include
For EF Core <=3.1, You have to do the filtering in memory as follows:
var customer = loyaltyContext.Customer
.Include(c => c.ContactInformation)
.Include(c => c.Address)
.Include(c => c.MarketingPreferences)
.Include(c => c.ContentTypePreferences)
.Include(c => c.ExternalCards)
.Where(c => c.CustomerInternalId == customerInternalId).First();
customer.ExternalCards = customer.ExternalCards.Where(ec => ec.CardStatus == "ACTIVE").ToList();
I have nested entities like Property -> Facility -> Farm -> License etc.
I want to get the most recent license and my original query looks like this.
return _db.Properties
.Include(c => c.Contact)
.Include(f => f.Facilities.Select(c => c.Contact))
.Include(f => f.Facilities.Select(ff => ff.Farms.Select(s => s.Species)))
.Include(x => x.Facilities.Select(l => l.Licenses))
.SingleOrDefault(x => x.PropertyID == id);
Since I want to get the most recent license I tried
return _db.Properties
.Include(c => c.Contact)
.Include(f => f.Facilities.Select(c => c.Contact))
.Include(f => f.Facilities.Select(ff => ff.Farms.Select(s => s.Species)))
.Include(x => x.Facilities.Select(l => l.Licenses.OrderByDescending(d => d.IssueDate)))
.SingleOrDefault(x => x.PropertyID == id);
which fails of course because you cant use an orderby clause there.
If I try an orderby clause at the end of the linq it will start at Property and I will need to drill down to the licenses again.
What is the preferred convention for this?
--EDIT--
Based on Robert's suggestion I flipped the query to get the Licenses first but I guess I need to do some projection since this query only gives me the Property entity and no child entities.
return _db.Licenses.OrderByDescending(x => x.IssueDate)
.Include(f => f.Facility)
.Include(f => f.Facility.Property)
.Include(f => f.Facility.Property.Contact)
.Include(c => c.Facility.Contact)
.Include(f => f.Facility.Farms)
.Include(f => f.Facility.Farms.Select(s => s.Species))
.Where(x => x.Facility.Property.PropertyID == id)
.Select(x => x.Facility.Property).SingleOrDefault();
Any ideas to get all children?
I am having an issue getting the records I need from 1 query using the include extension.
This is what is mostly working:
_db.Companies.Where(x => x.CompanyID == id)
.Include(x => x.Contact)
.Include(x => x.Properties.Select(p => p.Contact))
.Include(x => x.Properties.Select(f => f.Facilities.Select(c => c.Contact)))
.Include(x => x.Properties.Select( => f.Facilities.Select(s => s.Sections.Select(si => si.SectionIdeas))))
.SingleOrDefault();
This is fine except entity initiates a separate query for each license since I am not including it.
Since I would like to get the license in the same query I tried this:
_db.Companies.Where(x => x.CompanyID == id)
.Include(x => x.Contact)
.Include(x => x.Properties.Select(p => p.Contact))
.Include(x => x.Properties.Select(f => f.Facilities.Select(c => c.Contact)))
.Include(x => x.Properties.Select(f => f.Facilities.Select(l => l.Licenses)))//added
.Include(x => x.Properties.Select(f => f.Facilities.Select(s => s.Sections.Select(si => si.SectionIdeas))))
.SingleOrDefault();
This causes another row to be returned for each facility. Is there a way to get the license without additional rows?
I'm trying to do an include of a nested entity. I assumed the below code would work but it does not recognize the CapitalMailOrders entitycollection. Can anyone point me in the right direction to include these?
var result = db.Contacts
.Include(a => a.IDXPageLinks)
.Include(b => b.ReboGatewayLoginInfoes)
.Include(c => c.SocialMedias)
.Include(d => d.WebSiteInfoes)
.Include(e => e.ContactImages)
.Include(f => f.RealtorSetUpProcesses)
.Include(h => h.RealtorSetUpProcesses.CapitalMailOrders) // getting compile time error here. Doesn't recognize Entity
.Include(g => g.Contact_CarrierCode_Assignments)
.FirstOrDefault(c => c.ContactID == id);
Thanks
The extra entity level is accessed from a collection and so you need to add a Select in order to bring all the entries into the include.
.Include(h => h.RealtorSetUpProcesses.Select(h2 => h2.CapitalMailOrders)
I can't seem to find how to eager load multiple child child collections in EF. So I can do:
blawConext.Blaws
.Include(b => b.ChildCollection
.Select(cc => cc.ChildChildCollection)
)
I can even go deeper and deeper without a problem but I can't get the umm peer? collection, The below does not work
blawConext.Blaws
.Include(b => b.ChildCollection
.Select(cc => cc.ChildChildCollection1)
.Select(cc => cc.ChildChildCollection2)
)
You can specify multiple includes:
blawConext.Blaws
.Include(b => b.ChildCollection.Select(cc => cc.ChildChildCollection1))
.Include(b => b.ChildCollection.Select(cc => cc.ChildChildCollection2))