Dalla documentazione:
Entity Framework Core aggiusterà 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 ancora essere popolata se alcune o tutte le entità correlate fossero state precedentemente caricate.
Configurazione delle entità:
public class Page{
public Page () {
Event = new HashSet<Event>();
}
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; } // don't want to retrieve, too large
public ICollection<Event> Event { get; set; }
}
public class Event{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public Page Page { get; set; }
}
Il contesto è impostato con una relazione uno-a-molti.
Queste sono le domande che corro, una dopo l'altra:
var pages = _dbContext.Page.Select(page => new Page
{
Id = page.Id,
Title = page.Title
}).ToList();
var events = _dbContent.Event.ToList();
Mi aspetto che ogni Page
contenga la raccolta di Events
(e viceversa per Event
con il riferimento alla Page
), ma la correzione non si verifica (la Page
in Event
è null
e Event
in Page
è null
).
Se sostituisco la prima query, la correzione funziona:
var pages = _dbContext.Page.ToList();
Quindi sembra che con la proiezione la correzione non avvenga. Il motivo per cui ho diviso questo in 2 query è stato quello di evitare di utilizzare qualcosa come Include
che avrebbe reso un enorme join e duplicato un sacco di dati.
C'è un modo per aggirare questo? Devo eseguire manualmente la riparazione manualmente?
Quando si proietta in un nuovo tipo nella query, EF Core non traccia l'oggetto che esce dalla query anche se sono di tipo un'entità che fa parte del Modello. Questo è di design.
Dal momento che nel tuo caso le Page
non vengono tracciate, gli Events
non hanno nulla a che fare con il fixup. Quindi stai vedendo proprietà di navigazione nulla.
Questo comportamento era lo stesso nella versione precedente (EF6). Il motivo principale della mancata tracciabilità è, come nel tuo caso, la creazione di una nuova Page
senza caricare il Content
. Se tracciamo la nuova entità, il Content
sarà impostato su null
(predefinito (stringa)). Se contrassegni l'intera entità come modificata, SaveChanges
finirà per salvare il valore nullo nella colonna Content
nel database. Ciò causerebbe la perdita di dati. A causa di un errore minore potrebbe causare problemi importanti come la perdita di dati, EF Core non tiene traccia delle entità per impostazione predefinita. Un altro motivo sono i tipi di entità deboli (o tipi complessi in EF6) che condividono il tipo CLR con altre entità ma identificati univocamente tramite il tipo Parent
, se si proietta tale entità allora EF Core non può capire quale tipo di entità è senza informazioni padre.
Puoi mettere quelle entità in un changetracker chiamando il metodo Attach
, che causerà la correzione e otterrai il comportamento desiderato. Stai attento a non salvarli.
In generale lo scenario che vuoi è utile. Questo problema sta monitorando il supporto per questo in EF Core.
Non penso che dovrebbe funzionare. Hai verificato che questo comportamento funzionasse nelle versioni precedenti di EntityFramework? Dato che non stai estraendo l'intera entità, e solo le sue proprietà, e poi passandole in una nuova Entità, stai essenzialmente selezionando le proprietà e creando una nuova Entità.
Se desideri che questo sia collegato, puoi chiamare manualmente il Metodo Allegare dopo aver selezionato la tua pagina
var pages = _dbContext.Page.Select(page => new Page
{
Id = page.Id,
Title = page.Title
}).ToList();
pages.ForEach(p => _dbContext.Page.Attach(p));
Ricorda che se chiami SaveChanges dopo questo perderai le proprietà non scaricate, quindi usalo solo quando chiami Get
Methods