2015-12-17 12 views
5

EF7 doesn't support lazy loading of child objects, ma supporta la funzione .Include(). Detto questo, sto lottando con qualcosa e non sono sicuro che non sia possibile in EF7, o lo sto fissando da troppo tempo.ef7 non è in grado di recuperare le proprietà dell'oggetto figlio delle raccolte secondarie

qualcosa Supponiamo come il seguente (controllando reg.Activities.Task.Ordinal (un int), Task è sempre nullo, anche quando controllo il DB me stesso e sono certo che non v'è in realtà un record correlato) ...

public void SomeOtherMethod() 
    var r = getRegistration(User.UserName); 
    var act = r.Activities 
     .Where(a => a.IsDone == false) // unfinished 
     .OrderByDescending(o => o.Task.Ordinal) // Task indicates activity type, is always null 
     .FirstOrDefault(); // to get a user's most recent unfinished activity 

    //DO SOMETHING WITH ACT 
} 

public Registration getRegistration(string userName) { 
    var reg = _context.Registrations 
     .Where(r => r.User.UserName == userName) // this works however? 
     .Include(r => r.Acvitities) // List<Activity> 
     .FirstOrDefault(); 

     return reg; 
} 

... Ho il navigation properties in posto nelle classi del modello, ma lo .Task è null e non caricato.

Inoltre, dato che la query è stata progettata, non posso .Include proprietà aggiuntive più nella creazione di act. Non posso .ThenInclude nella creazione di reg perché la classe Registration non include una definizione per una proprietà Task (ma Registration ha una collezione di Activities che sono List<Activity>, e Activity ha un Task che è legato ad un altro tavolo/classe che definisce il compiti e l'ordine in cui devono essere presentate agli utenti per Activity.

ho provato vari incantesimi di .Join, .Include e .ThenInclude sperando di essere in grado di aderire al Task a ciascuno dei Activities mentre ritorna l'oggetto Registration, ma questo fallisce perché Registration stesso non contiene una proprietà Task.

Ho preso in considerazione la creazione di un nuovo problema su GitHub, ma non sono ancora sicuro che non sia molto fattibile e non lo sto guardando correttamente.


Update1: Mihail ha suggerito di utilizzare ...
.Include(r => r.Activities.Select(resp => resp.Responses))
... ma questo produce un'eccezione. Questo SO (https://stackoverflow.com/a/30151601/3246805) indica questo per EF5 e che deve essere utilizzato .ThenInclude.

Tuttavia, cercando quel suggerimento ...
.ThenInclude(r => r.Select(t => t.Task))
... si ottiene la seguente eccezione ...

The properties expression 'r => {from Activity t in r select [t].Task}' is not valid. The expression should represent a property access: 't => t.MyProperty'. When specifying multiple properties use an anonymous type: 't => new { t.MyProperty1, t.MyProperty2 }'. 
Parameter name: propertyAccessExpression 



UPDATE2: Stafford ha chiesto per lo schema. Miglior risultato in un repo condivisibile ...

public class RegistrationData { 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

    [Required] 
    public MyUser User { get; set; } // MyUser : IdentityUser 

    //blah blah, more fields 

    public List<UserTask> Activitys { get; set; } 
} 

public class UserTask { 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    [Required] 
    public bool IsDone { get; set; } = false; 

    [Required] 
    public int RegistrationId { get; set; } 
    [Required] 
    public RegistrationData Registration { get; set; } 

    [Required] 
    public int TaskId { get; set; } 
    [Required] 
    public Task Task { get; set; } 

    public List<UserResponse> Responses { get; set; } 
} 

public class Task { 
    [Required] 
    [DatabaseGenerated(DatabaseGeneratedOption.None)] // ID comes from loaded config 
    public int Id { get; set; } 

    [StringLength(20, MinimumLength = 1)] 
    public string Name { get; set; } 

    [Required] 
    public int Ordinal { get; set; } 

    [Required] 
    public int GroupId { get; set; } 
} 

public class UserResponse { 
    [Required] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    [Required] 
    public int UserTaskId { get; set; } 
    [Required] 
    public int QuestionNumber { get; set; } 
} 
+0

si dovrebbe avere un altro riga come questa: .include (r => r.Acvitities.Select (t => t.Task)), dopo l'inclusione delle attività –

+0

@MihailStancescu uomo che sembrava bello e Speravo che potesse risolverlo, ma sta creando un'eccezione in getRegistration quando si crea la variabile 'reg' ...'Impossibile eseguire il cast dell'oggetto di tipo 'Remotion.Linq.Clauses.Expressions.SubQueryExpression' per digitare 'System.Linq.Expressions.MemberExpression'' –

risposta

12

Usa Include seguito da ThenInclude per proprietà secondarie del bambino. Le proprietà secondarie potrebbero non essere visualizzate in intellisense per ThenInclude, ma è sufficiente inserirla comunque - si compilerà e opererà come previsto.

var reg = _context.Registrations 
    .Where(r => r.User.UserName == userName) 
    .Include(r => r.Acvitities).ThenInclude(a => a.Task) 
    .Include(r => r.Activities).ThenInclude(a => a.SomethingElse) 
    .FirstOrDefault(); 
    return reg; 
+0

Questo è così vicino a ciò di cui ho bisogno! In effetti risolve il problema della proprietà Task! Ho provato ad usare lo stesso concetto per poi raccogliere una proprietà addizionale dallo stesso oggetto che è un 'Elenco' di oggetti. Senza fortuna Idee? Possono esserci più '.ThenInclude's? Sembra che dovrebbe essere fattibile, non lo sto facendo bene. Le seconde catene del precedente (la classe Task). Un altro '.Include (r => r.Acvitities)' non sembra proprio giusto. –

+0

@ t.j. Possono esserci multipli '.Include (qualcosa). ThenInclude (qualcosa)'. Mostra il tuo schema e quali proprietà/quali stai cercando di includere. –

+0

Questo suggerisce che è fattibile ... https://github.com/aspnet/EntityFramework/issues/2274 –

Problemi correlati