In this article, we will learn when the “call is ambiguous” error happens, why the error happens, and how to work around the issue. There are still so many legacy projects using older versions of EF Core, and in those projects, this error can cause a lot of headaches for developers if they are not aware of how to resolve it.
So, let’s start and see what we can do about it.
When Does the Issue Happen?
One example is when we use Entity Framework Core
version 5 and System.Linq.Async
Nuget packages. Entity Framework Core
version 6 or later package already resolves the issue, and we will explain that later in this article.
The sample application is a .NET 7
console application and it has both Entity Framework Core (EF Core) version 5
and System.Linq.Async version 6
libraries.
So, let’s start with querying the DbSet
from the DbContext
:
blogDbContext.Articles.Where(x => x.Title == "Some Title");
Right after we write the code, we see the “call is ambiguous” error message on the Where
method.
Why Does the Issue Happen?
The issue happens when an instance of the class has more than one method with the same name. But how can an instance have more than one method with the same name? The answer is – The C# extension method feature.
By using the feature, we can add custom methods to existing interfaces and classes. If you are unfamiliar with the feature, please refer to the Static Members, Constants and Extension Methods in C# article.
Multiple Where Methods in the Interface
Now, let’s inspect the interfaces that contain the Where
method.
The System.Linq
adds Where
method to the IQueryable<TSource>
interface. Similarly, the System.Linq.Async
library adds Where
method to the IAsyncEnumerable<TSource>
interface.
The DbSet<TEntity>
class inherits from both IQueryable<TEntity>
and IAsyncEnumerable<TEntity>
interfaces. As a result, the DbSet<TEntity>
class ends up having two Where
methods.
This also applies to other methods such as FirstAsync
, FirstOrDefaultAsync
, etc. Of course, the cause and the solutions are the same as for the Where
method, so we will focus on the Where
method’s case in this article.
How to Work Around the Issue?
There are several ways to work around the issue.
Use Explicit Casting
The first workaround is to use the explicit cast.
Let’s change the code:
((IQueryable<Article>)blogDbContext.Articles).Where(x => x.Title == "Some Title");
Because we explicitly cast the blogDbContext.Articles
to IQueryable<Article>
, the compiler knows which Where
method to use.
Let’s try to cast to another interface as well:
((IAsyncEnumerable<Article>)blogDbContext.Articles).Where(x => x.Title == "Some Title");
Again, we don’t encounter the error.
Use AsQueryable And AsAsyncEnumerable Methods
The Entity Framework Core
library provides AsQueryable
and AsAsyncEnumerable
methods to work around the issue so that we don’t need to use the explicit cast:
blogDbContext.Articles.AsQueryable().Where(x => x.Title == "Some Title"); blogDbContext.Articles.AsAsyncEnumerable().Where(x => x.Title == "Some Title");
Both methods work as expected and we don’t encounter the issue. Basically, what this does is the same with explicit casting, but the code is more clear with fewer parenthesis!
Upgrade to Entity Framework Core Version 6 or Later
After Entity Framework Core 6
, the IAsyncEnumerable<TEntity>
interface inheritance was removed from the DbSet
class. Therefore, if we upgrade the version of EF Core, we won’t encounter this ambiguity issue anymore.
Conclusion
In this article, we’ve learned when and why the “call is ambiguous” issue happens. Whenever you encounter the same issue in the future, we hope this article helps you to solve the issue.