简体   繁体   中英

How to explicit loading long navigation properties' chain using Entity Framework?

I have this code to explicit loading for an entity:

dbContext.StorageRequests.Add(storageRequest);
dbContext.SaveChanges();
//Here I want to explict loading some navigation properties
dbContext.Entry(storageRequest).Reference(c => c.Manager).Load();
dbContext.Entry(storageRequest).Reference(c => c.Facility).Load();
dbContext.Entry(storageRequest).Collection(x=> x.PhysicalObjects).Query().Include(x => x.Classification).Load();

My question is two parts:

The first one how can I load all together (I want to call Load() once)?

The second part does the above code sends query for each Load() calling which in turn hit the database to load related data?

I had a similar question withEF core. Turning on SQL logging to the debugoutput window helped answer a lot of my questions as to what it was doing, and why. In terms of your questions:

1) You can't, though you can eager load it with a series of dbContext.Collection.Include(otherCollection).ThenInclude(stuffRelatedToOtherCollection) type chains

2) Yes it does, even eager loading in one c# statement bangs out multiple queries. I presumed this was because it's too much of a complex artificial intelligence problem to do it any way other than its most naive multiple-sql, because it's hard for the framework to deal with cartesian products when multiple tables are joined together in one rectangular dataset. (A school has students and teachers, teacher:students is a many:many relationship, decomposed by class. If you wrote one query to join school, class, student and teachers, you'd get repeated data all over the place and though conceptually possible to pick through it looking for unique school, class teacher and student primary key values, you could be downloading tens of thousands of duplicated rows only to have to unique them all again. EF tends to select the school ,then school join class, then school join class join students, then school join class join teachers (if that's how you coded your school include class theninclude students then include teachers. Changing your include strategy will change the queries that are run)

Nice question! Let me answer differently, in reverse order, with new info.

2.)

Each Load() will cause a query to the database as of the documentation ( Querying and Finding Entities - 10/23/2016):

A query is executed against the database when:


People often useseager loading with Include() to let EF optimize as much as possible:

in most cases, EF will combine the joins when generating SQL

// ef 6
using System.Data.Entity;

var storageRequests = dbContext.StorageRequests
    .Include(r => r.PhysicalObjects.Select(p => p.Classification))
    .Include(r => r.Manager)
    .Include(r => r.Facility);

// evaluate "storageRequests" here by linq method or foreach

or:

// ef core
var storageRequests = dbContext.StorageRequests
    .Include(r => r.PhysicalObjects)
    .ThenInclude(p => p.Classification)
    .Include(r => r.Manager)
    .Include(r => r.Facility);

// evaluate "storageRequests" here by linq method or foreach

1.)

Only possible way I can imagine is having above code with storageRequests.Load() . You could inspect whether it:

  • generates single/multiple queries,
  • loads navigation property data along StorageRequest .

FYI: these query executions are also called network roundtrips in microsoft docs:

Multiple network roundtrips can degrade performance, especially where latency to the database is high (for example, cloud services).


Point of interest:

There is a relative new option Single vs. Split Queries (10/03/2019) in .Net Core 5.

The default is single queries (behavior described above). After that you can decide to request/load data per table instead, by adding .AsSplitQuery() to your linq query, before the evaluation. Splitted queries increases roundtrips and memory usage (does not loads distinct data) but helps performance.

There is also .AsSingleQuery() if your global choice was:

.UseSqlServer(
    connectionString,
    o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM