3

Let's say I have a query in EF Core that looks like so:

MethodWithDomainLogic() {
  return this.dbContext.People.Where(...).ToListAsync();
}

Now, in an effort to decouple my domain layer from my data access layer, I want this method to be in my domain assembly and that assembly not to have a reference to EFCore. So it would look like:

In Domain Layer:

public interface IEntities {
  IQueryable<Person> People { get; set; }
}

In Data Layer:

private IEntities entities; // injected with a dbcontext that implements the IEntities interface.

public Task<IEnumerable<Person>> MethodWithDomainLogic() {
  return this.entities.People.Where(...).ToListAsync(); // How to do this without referencing EFCore?
}

From my understanding, this is impossible since Linq does not support async queries on it's own.

I have solved this by setting up an interface of my own in the domain layer with the EFCore interface (basically copied and pasted the methods like ToListAsync and FirstAsync and etc...) and then implement it in my data layer with just a call to the EFCore version of this. However, that is very messy and complicated.

Is there a better solution? I want my domain method to use async programming and Linq without EFCore but for that Linq/async programming to be implemented with EFCore in the data layer.

Ian Kirkpatrick
  • 1,861
  • 14
  • 33

1 Answers1

5

Many of the query methods that you will need to use from your domain layer are defined in EF, not elsewhere in the framework. ToListAsync(), Include(navprop), AsNoTracking(), etc.

If you are composing queries in your domain layer, as you definitely should, and you want to access the full range of useful EF funtionality, you need a reference to EF.

It's possible to not have a reference to EF, and just use the subset of IQueryable<T> extension methods defined in the base framework, but that has a cost. And it's possible to put some sort of custom intermediate API between your domain and EF, but again the question is whether it's worth the effort.

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67
  • Yeah, I've gotten around the issue by adding a service that basically copies the async interface for IQueryable such as ToListAsync and FirstAsync but I am looking for a more native way to do it. Also, what do you mean by "the subset of IQueryable extension methods defined in the base framework"? Are you referring to just basic linq operations such as ToList()? If so, I assume the cost you're talking about is that it uses blocking queries rather than async queries – Ian Kirkpatrick May 18 '20 at 18:35
  • As for whether it's worth it... as for this specific app, I plan to have a web app, a desktop app and a mobile app. I also don't want to require the user to be hooked up to the web for the desktop apps so they would need a file storage rather than a DB storage... which means a totally different data layer – Ian Kirkpatrick May 18 '20 at 18:36
  • Yes. The cost of having to work around not having those features. Note, also, though that there are different EF providers you can use in different environments. For instance on the desktop you can use the SQLite provider. https://learn.microsoft.com/en-us/ef/core/providers/sqlite/?tabs=dotnet-core-cli – David Browne - Microsoft May 18 '20 at 18:50