In your code you are requesting Offer and tell the EF.Core to include OfferLocations property. The OfferLocation references back the requested Offer object this why it got set. If you want to have Location to be included in this request you have to use ThenInclude method right after Include one. E.g. if you were using the database context to retrieve the data it could look like this:
context.Offers
.Include(o => o.OfferLocations)
.ThenInclude(ol => ol.Location)
.FirstOrDefaultAsync(o => o.Id == id);
But with the generic repository approach you pass the collection of include expressions as the Expression<Func<T, object>>[] includeExpression which obviously doesn't let you use ThenInclude.
You can use the approach described in this answer.
public Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null,
CancellationToken cancellationToken = default)
{
IQueryable<TEntity> query = this.DbSet;
if (include != null)
{
query = include(query);
}
if (predicate != null)
{
query = query.Where(predicate);
}
return query.FirstOrDefaultAsync(cancellationToken);
}
Usage:
var offer = await this.unitOfWork.Offers.FirstOrDefaultAsync(
predicate: o => o.Id == id,
include: source => source
.Include(o => o.Partner)
.Include(o => o.SubCategory)
.Include(o => o.Category)
.Include(o => o.OfferItems)
.Include(o => o.OfficeLocations)
.ThenInclude(ol => ol.Location));