I have the following code to fetch data.
Note how I have used the null coalescing operator ?? to substitute a dummy clinic if childClinic.Clinic is null so I can still use ThenInclude() on the Clinic nav properties.
I don't like this and I'm not sure it will work.
My questions are:
NB: Entities returned will not have change tracking. They will be read only. I have not included the code for CreateBaseQueryable method here as it only returns the DbContext as IQueryable.
Thanks in advance.
    List<Child> children = await CreateBaseQueryable(context, healthBoardId)
        .Include(child => child.ChildStatuses)
        .Include(child => child.ChildClinics)
            .ThenInclude(childClinic => childClinic.Clinic ?? new Clinic())
                .ThenInclude(clinic => clinic!.Base)
        .Include(child => child.ChildClinics)
            .ThenInclude(childClinic => childClinic.Clinic ?? new Clinic())
                .ThenInclude(clinic => clinic!.Board)
        .Where(child => child.ChildStatuses.Any(status => status.ACounter >= 2))
        .Where(child => child.ChildClinics.Any(
            clinic => !clinic.IsDeleted &&
            clinic.Clinic != null &&
            (
              clinic.Clinic.ClinicType == (int)ClinicType.Type1||
              clinic.Clinic.ClinicType == (int)ClinicType.Type2)
            )
         )
         .ToListAsync();
I have the following code to fetch data.
Note how I have used the null coalescing operator ?? to substitute a dummy clinic if childClinic.Clinic is null so I can still use ThenInclude() on the Clinic nav properties.
I don't like this and I'm not sure it will work.
My questions are:
NB: Entities returned will not have change tracking. They will be read only. I have not included the code for CreateBaseQueryable method here as it only returns the DbContext as IQueryable.
Thanks in advance.
    List<Child> children = await CreateBaseQueryable(context, healthBoardId)
        .Include(child => child.ChildStatuses)
        .Include(child => child.ChildClinics)
            .ThenInclude(childClinic => childClinic.Clinic ?? new Clinic())
                .ThenInclude(clinic => clinic!.Base)
        .Include(child => child.ChildClinics)
            .ThenInclude(childClinic => childClinic.Clinic ?? new Clinic())
                .ThenInclude(clinic => clinic!.Board)
        .Where(child => child.ChildStatuses.Any(status => status.ACounter >= 2))
        .Where(child => child.ChildClinics.Any(
            clinic => !clinic.IsDeleted &&
            clinic.Clinic != null &&
            (
              clinic.Clinic.ClinicType == (int)ClinicType.Type1||
              clinic.Clinic.ClinicType == (int)ClinicType.Type2)
            )
         )
         .ToListAsync();
Include and ThenInclude don't care if the properties are null/nullable or not, just for the sake of issuing an INNER vs an LEFT JOIN. It's not the same as LINQ to Objects, or when you access a null property directly.
To expand on Ricardo's answer: When you use Linq to build a query, the use of Include, ThenInclude, and even Select, is not limited to whether a related entity or property is available or not. These functions ultimately are used to produce an SQL statement that will result in data coming back. So you just need:
.Include(child => child.ChildClinics)
    .ThenInclude(childClinic => childClinic.Clinic)
        .ThenInclude(clinic => clinic.Base)
.Include(child => child.ChildClinics)
    .ThenInclude(childClinic => childClinic.Clinic)
        .ThenInclude(clinic => clinic.Board)
When you go through the list of resulting Child entities then you need to account for the possibility of a null child clinic and/or Base/Board.  The same goes for using Select when projecting data. If you wanted a Clinic.Base.Name and Clinic.Board.Name:
.Select(child => new ChildDto
{
    ChildId = child.Id,
    // ...
    ClinicBaseName = child.ChildClinic.Base.Name,
    ClinicBoardName = child.ChildClinic.Board.Name
}).ToList();
Attempting to use child?.ChildClinic?.Base?.Name won't translate down to SQL. EF will populate a default value if any of the navigation properties are #null.


??causes issues. LINQ queries don't get executed themselves. The LINQ query gets translated to SQL, where NULL behaves very differently from programming languages. – Panagiotis Kanavos Commented Jan 29 at 9:36nullnavigation properties. To me, it remains a question if you should want to replace null Clinics bynew Clinic(). Personally, I'd prefer not to. – Gert Arnold Commented Jan 30 at 15:40