Assuming you have Navigation Properties configured correctly then this should work:
(I note that EF6 and EF Core's scaffolding templates (for auto-generating entity classes from an existing database) do this for you already.)
(Also, I really don't like C#'s keyword-style Linq expressions because in order to do almost anything you need to tack-on Linq extension-methods, which clashes aesthetically with keyword-style expressions. I can't think of any good reason to use keyword-style Linq expressions thesedays, honestly).
I assume _db is your DbContext.
using System.Linq;
using System.Data.Entity; // for EF6
using Microsoft.EntityFrameworkCore.Query; // for EF Core
A a = await _db.A
.Include( a => a.B )
.Include( a => a.B.C )
.Include( a => a.B.C.D )
.Where( a => a.IdA == param )
.SingleOrDefaultAsync();
// b, c, and d can then be gotten from A:
B b = a.B;
C c = a.B.C;
D d = a.B.C?.D; // It looks like A.B and B.C are INNER JOIN while C.D is LEFT OUTER JOIN. Linq will use the correct JOIN type (INNER, LEFT, etc) based on your model configuration. You cannot tell from the query alone.
return new DTOFin() { ... };
If you don't have navigation properties set-up (and you should...) then you can do Joins manually - but it is noticably more gnarly because Linq's .Join method was never intended to be used directly because you're expected to use Navigation Properties instead.
- Note that because this Linq query is being used with Entity Framework it means your query must be representable in SQL...
- Which it means that certain limitations apply: such as not using the
?. operator - which is your issue.
- Other limitations include not being able to use your own custom predicate functions (unless they're also
Expression<Func<>>) because you can't just put C# code into a SQL query.
I believe the below query should work, but I cannot say for certain without knowing more about your EF model configuration and database design - you haven't provided enough detail in your opening question post.
var a_b_c_d = await _db.A
.Join( _db.B, a => a.IdA , b => b.IdB1, ( a , b ) => new { a, b } )
.Join( _db.C, a_b => a_b.b.IdB2 , c => c.IdC1, ( a_b , c ) => new { a_b.a, a_b.b, c } )
.Join( _db.D, a_b_c => a_b_c.c.IdC2, d => d.IdD , ( a_b_c, d ) => new { a_b_c.a, a_b_c.b, a_b_c.c, d } )
.Where( a_b_c_d => a_b_c_d.a.IdA == param )
.SingleOrDefaultAsync();
A a = a_b_c_d.a;
B b = a_b_c_d.b;
C c = a_b_c_d.c;
D d = a_b_c_d.d;
return new DTOFin() { ... };
awaitallAsyncLinq methods. Entity Framework does not support concurrent queries, so your code should be likevar a = await _db.A.FirstOrDefaultAsync(a => a.IdA == param);.context.Employees.Where(e => e.Department.Manager.LengthOfService > 10)to find all employees working for a manager who has served longer than 10 years