Okay so I have records to be used as DTOs
public record ProviderRecord(int ProviderId, string Name, DateTimeOffset InsertTimeStamp, IEnumerable<ModelRecord> models);
public record ModelRecord(int ModelId, string Name, string Version, DateTimeOffset InsertTimeStamp);
So I know in EF you can do an expression before the EF evaluates like so:
public async Task<IEnumerable<ProviderRecord>> GetAllProviders() =>
await _context.Providers
.Include(x => x.Models)
.ThenInclude(x => x.ModelScores)
.Select(SelectProvider) //Works yay!
.ToListAsync();
private Expression<Func<Provider, ProviderRecord>> SelectProvider = x => new ProviderRecord(x.ProviderId, x.Name, x.InsertTimeStamp, null);
However I swore I used to be able to chain expressions inside another expression like so:
public static Expression<Func<Provider, ProviderRecord>> SelectProvider = x => new ProviderRecord(x.ProviderId, x.Name, x.InsertTimeStamp,
x.Models.Select(SelectModels) //Doesn't work but I want to pre evaluate?
//x.Models.Select(y => new ModelRecord(y.ModelId, y.Name, y.Version, y.InsertTimeStamp)) //This work but it's long form inline
//GetModelRecords(x.Models.ToList()) //Does work but I don't want this
);
public static List<ModelRecord> GetModelRecords(List<Model> models) => models.Select(model => new ModelRecord(model.ModelId, model.Name, model.Version, model.InsertTimeStamp)).ToList();
public static Expression<Func<Model, ModelRecord>> SelectModels = y => new ModelRecord(y.ModelId, y.Name, y.Version, y.InsertTimeStamp);
Any EF warriors out there that know something. I can do it inline but that is a pain for resuse and visually if I then introduce a third or fourth level of a tree. But I may have to...
Try using AsQueryable
on x.Models
:
// ...
x.Models.AsQueryable().Select(SelectModels)
If this does not work then another option is to use 3rd party library like LINQKit:
// ...
x.Models.Select(x => SelectModels.Invoke(x))
And do not forget to call AsExpandable
on source IQueryable
.