Sto tentando di caricare una modale correlata in Entity Framework Core, ma per qualche motivo è stata caricata una raccolta nidificata quando non l'ho richiesta nella chiamata Include()
.
Ecco i miei due modelli -
Driver.cs
public partial class Driver : IBaseEntity
{
public short DriverId { get; set; }
public string Surname { get; set; }
public string Initials { get; set; }
public byte DriverStatusTypeId { get; set; }
public DriverStatusType DriverStatusType { get; set; }
}
DriverStatusType.cs
public partial class DriverStatusType
{
public DriverStatusType()
{
Drivers = new HashSet<Driver>();
}
public byte DriverStatusTypeId { get; set; }
public string DriverStatusTypeName { get; set; }
public string Description { get; set; }
public ICollection<Driver> Drivers { get; set; }
}
DriversService.cs
public class DriverService : IDriverService
{
public DriverService(MyContext context)
{
Context = context;
}
public MyContext Context { get; }
public async Task<IEnumerable<Driver>> GetAllDrivers()
{
var drivers = await Context
.Drivers
.Include(d => d.DriverStatusType)
.toListAsync();
return drivers;
}
public async Task<Driver> GetDriverById(int id)
{
var driver = await Context
.Drivers
.Include(d => d.DriverStatusType)
.Where(d => d.DriverId == id)
.FirstOrDefaultAsync();
return driver;
}
}
Ora quando chiamo il GetDriverById(int id)
dal mio controller, riprendo quello che mi aspetto -
{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers": []
}
}
Tuttavia, il metodo GetAllDrivers()
restituisce la raccolta dei drivers
nidificati drivers
che significa che i dati che sto recuperando sono enormi -
[
{
"driverId": 1,
"surname": "Stark",
"initials": "T",
"displayText": "Tony Stark",
"driverStatusTypeId": 2,
"driverStatusType": {
"driverStatusTypeId": 2,
"driverStatusTypeName": "Available",
"description": "This driver is available",
"drivers": [
{
"driverId": 2,
"surname": "Rogers",
"initials": "S",
"driverStatusTypeId": 2
},
{
"driverId": 3,
"surname": "Romanoff",
"initials": "N",
"driverStatusTypeId": 2
},
{
"driverId": 4,
"surname": "Banner",
"initials": "B",
"driverStatusTypeId": 2
},
...
Ho pensato che l'idea di caricare con impazienza fosse solo includere i relativi modelli specificati nell'istruzione di inclusione, ma sembra che questo non sia il caso. Qualcuno potrebbe spiegare cosa sta succedendo qui?
Ho pensato che l'idea del caricamento desideroso fosse di includere solo i modelli correlati specificati nell'istruzione include, ma sembra che non sia così. Qualcuno potrebbe spiegare cosa sta succedendo qui?
Hai ragione, non è così. L'idea del caricamento desideroso è garantire che vengano caricati i dati correlati specificati. Non significa / garantisce che i dati correlati non saranno inclusi.
È parzialmente spiegato nella sezione Caricamento dei dati correlati della documentazione EF Core:
Mancia
Entity Framework Core correggerà automaticamente le proprietà di navigazione su qualsiasi altra entità precedentemente caricata nell'istanza di contesto. Pertanto, anche se non includi esplicitamente i dati per una proprietà di navigazione, la proprietà potrebbe comunque essere popolata se alcune o tutte le entità correlate sono state precedentemente caricate.
La correzione della proprietà di navigazione significa che ogni volta che si materializza l'istanza dell'entità, tutte le proprietà di navigazione correlate vengono aggiornate per rispecchiarla, ad esempio Driver
viene aggiunto a Driver.DriverStatusType.Drivers
e viceversa.
Si noti che quando si utilizzano query di tracciamento, ciò può accadere dopo la materializzazione della query non inclusa ( ToList()
) poiché il tracker modifiche tiene traccia dei riferimenti agli oggetti e li aggiorna automaticamente quando si eseguono altre query di tracciamento.
Un altro effetto di quel processo di correzione è che quando si include una delle estremità della relazione, la proprietà di navigazione inversa dell'altra estremità viene automaticamente popolata.
Quindi, anche se nel primo caso la proprietà Drivers
deve essere popolata e contenere un singolo elemento. E questo è ciò che sta realmente accadendo nei miei test puliti, non sai perché stai ottenendo la differenza - potrebbe essere il serializzatore che lo nasconde?
Comunque, tutto ciò significa che non puoi davvero controllare il contenuto delle proprietà di navigazione. L'unico modo in cui puoi controllare esattamente cosa stai restituendo è utilizzare speciali classi DTO / ViewModel ecc. E la proiezione ( Select
).