2015-12-17 9 views
5

EF7 doesn't support lazy loading of child objects, ale obsługuje funkcję .Include(). Mówiąc o tym, mam problemy z czymś i nie jestem pewien, czy to nie jest możliwe w EF7, czy właśnie patrzyłem na to zbyt długo.ef7 nie może pobrać właściwości obiektu podrzędnego obiektów kolekcji dziecięcej:

Załóżmy coś jak poniżej (sprawdzanie reg.Activities.Task.Ordinal (an int), Zadanie jest zawsze pusty, nawet kiedy sprawdzić DB siebie i jestem pewien, że w rzeczywistości jest związana rekordu) ...

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; 
} 

... Mam navigation properties na miejscu w klasach modeli, ale powyższe .Task ma wartość null i nie jest załadowane.

Ponadto, ponieważ zapytanie zostało rzucone, nie mogę już więcej dodawać żadnych właściwości w tworzeniu . I cant .ThenInclude w tworzeniu reg ponieważ klasa Registration nie zawiera definicji nieruchomości Task (ale Registration ma kolekcję Activities które są List<Activity> i Activity ma Task która jest powiązana z innej tabeli/klasy, który definiuje zadania i porządek powinny być przedstawiane użytkownikom za Activity.

próbowałem różne zaklęcia .Join, .Include i .ThenInclude nadzieję, aby móc przystąpić do Task do każdego z Activities wracając obiekt Registration, ale ten kończy się niepowodzeniem, ponieważ Registration samo w sobie nie zawiera właściwości Task.

Zastanawiam się nad stworzeniem nowego wydania na GitHubie, ale nie jestem jeszcze pewien, czy to nie jest wykonalne i po prostu nie patrzę na to poprawnie.


UPDATE1: Mihail zasugerował użycie ...
.Include(r => r.Activities.Select(resp => resp.Responses))
... ale to daje wyjątek. To SO (https://stackoverflow.com/a/30151601/3246805) wskazuje, że należy stosować EF5 i że .ThenInclude.

jednak próbuje tę sugestię ...
.ThenInclude(r => r.Select(t => t.Task))
... daje następujący wyjątek ...

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 hasła schematu. Best effort łatwością udostępniać w repo ...

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

Powinieneś mieć inny linię: .Include (r => r.Acvitities.Select (t => t.Task)), po to z działań –

+0

@MihailStancescu Człowiek, który wyglądał pięknie i Miałem nadzieję, że to rozwiąże, ale jest to zgłaszanie wyjątku w getRegistration podczas tworzenia zmiennej 'reg' ..."Nie można rzucić obiektu typu" Remotion.Linq.Clauses.Expressions.SubQueryExpression ", aby wpisać" System.Linq.Expressions.MemberExpression'' –

Odpowiedz

12

Zastosowanie Include następnie ThenInclude do właściwości podrzędnych dziecka. Właściwości podrzędne mogą nie pojawiać się w intellisense dla ThenInclude, ale po prostu wprowadź je mimo to - skompiluje i będzie działać zgodnie z oczekiwaniami.

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

To jest tak blisko tego, czego potrzebuję! W rzeczywistości rozwiązuje problem właściwości Task! Próbowałem użyć tej samej koncepcji, aby następnie zebrać dodatkową właściwość z tego samego obiektu, który jest "Listą" obiektów. Bez szczęścia. Pomysły? Czy może być wiele '.ThenInclude's? Wygląda na to, że powinno być wykonalne, po prostu nie rozumiem. Drugi łańcuch poprzedza (klasa Zadanie). Kolejne ".Include (r => r.Acvitities)" również nie wydaje się właściwe. –

+0

@ t.j. Może istnieć wiele '.Include (something) .TenInclude (something)'. Pokaż swój schemat i właściwości, które próbujesz uwzględnić. –

+0

Sugeruje to, że jest to możliwe ... https://github.com/aspnet/EntityFramework/issues/2274 –

Powiązane problemy