Taken from comments:
"Most read queries will populate a domain object. So, they don't simply return all columns. It'll be to build the entity.
I used to have repositories return IQueryable because I could build additional queries on top of it. The result was fast and direct because it's just one SQL statement at the end. The downside is un-managed code around. When "additional queries" need to be changed, they could be everywhere! Nowadays I only have GetById() in my repositories to populate domain objects from data, as what @Greg said.
The rest actions in the repo are just insert, update, or delete. I need the repositories because there are additional logics I like to perform beside inserting, etc. E.x., logging, saving events.
On the read side, you can use dbContext directly to build view models for each view. That way you can grab anything you need and they're specific for each view. You can choose different technologies too on read and write side. You can use Dapper for reading/building view models and EF Core for committing/persistence.
A lot of people go with a Repository, Context, then a Factory. So the Repository would hold the method or contract as an interface. The context would represent the implementation. Then the factory would be the instantiation of the implementation. So you would have syntax like using(var context = new SampleContext().Create()) { return context.RetrieveSampleModels()); } "