efcore: System.Interactive.Async call is ambiguous error when IX-Async is referenced
I’m using .NET Core 3.0 with EF Core and System.Interactive.Async. Using methods like FirstOrDefaultAsync and Where results in compilation errors like
The call is ambiguous between the following methods or properties: 'Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync<TSource>(System.Linq.IQueryable<TSource>, System.Linq.Expressions.Expression<System.Func<TSource, bool>>, System.Threading.CancellationToken)' and 'System.Linq.AsyncEnumerable.FirstOrDefaultAsync<TSource>(System.Collections.Generic.IAsyncEnumerable<TSource>, System.Func<TSource, bool>, System.Threading.CancellationToken)'
The call is ambiguous between the following methods or properties: 'System.Linq.Queryable.Where<TSource>(System.Linq.IQueryable<TSource>, System.Linq.Expressions.Expression<System.Func<TSource, bool>>)' and 'System.Linq.AsyncEnumerable.Where<TSource>(System.Collections.Generic.IAsyncEnumerable<TSource>, System.Func<TSource, bool>)'
Steps to reproduce
- Reference EFCore.
- Reference System.Interactive.Async
public class FruitDb : DbContext
{
public DbSet<Apple> Apples { get; set; }
public async Task Seeds5Async()
{
Apple apple = await Apples.FirstOrDefaultAsync(x => x.NumSeeds == 5);
// ... use it
}
}
Further technical details
EF Core version: 3.0.0 Database provider: Sqlite Target framework: .NET Core 3.0 Operating system: Windows 10 IDE: Visual Studio 2019 16.3
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 4
- Comments: 66 (27 by maintainers)
Links to this issue
Commits related to this issue
- Add explicit AsAsyncEnumerable and AsQueryable methods to DbSet Issue #18124 Helps avoid conflicts when also using IX-Async. No new tests since several existing tests now bind to these methods. — committed to dotnet/efcore by ajcvickers 5 years ago
- Add explicit AsAsyncEnumerable and AsQueryable methods to DbSet Issue #18124 Helps avoid conflicts when also using IX-Async. No new tests since several existing tests now bind to these methods. — committed to dotnet/efcore by ajcvickers 5 years ago
- fix: remove ambiguity for ef linq statements see https://github.com/dotnet/efcore/issues/18124 — committed to koenmetsu/organisation-registry by koenmetsu 4 years ago
- fix: remove ambiguity for ef linq statements see https://github.com/dotnet/efcore/issues/18124 — committed to Informatievlaanderen/organisation-registry by koenmetsu 4 years ago
- Refactor and improve async documentation * Merge query and saving async pages * Move under fundamentals * Document ambiguous invocation issues with System.Interactive.Async and show workaround. Cl... — committed to dotnet/EntityFramework.Docs by roji 4 years ago
- Refactor and improve async documentation * Merge query and saving async pages * Move under fundamentals * Document ambiguous invocation issues with System.Interactive.Async and show workaround. Cl... — committed to dotnet/EntityFramework.Docs by roji 4 years ago
- Refactor and improve async documentation * Merge query and saving async pages * Move under fundamentals * Document ambiguous invocation issues with System.Interactive.Async and show workaround. Cl... — committed to dotnet/EntityFramework.Docs by roji 4 years ago
- Refactor and improve async documentation * Merge query and saving async pages * Move under fundamentals * Document ambiguous invocation issues with System.Interactive.Async and show workaround. Cl... — committed to dotnet/EntityFramework.Docs by roji 4 years ago
- Refactor and improve async documentation (#2605) * Refactor and improve async documentation * Merge query and saving async pages * Move under fundamentals * Document ambiguous invocation issues ... — committed to dotnet/EntityFramework.Docs by roji 4 years ago
- Add `System.Linq.Async` package to work with `AsyncEnumerable` and `AsyncEnumerator` (this introduces an ambiguaty, see https://github.com/dotnet/efcore/issues/18124, which will be removed in EF Core ... — committed to building-envelope-data/metabase by simon-wacker 3 years ago
@shravan2x - Ways to deal with this
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync(Apples, x => x.NumSeeds == 5)@smitpatel Your answer is not helpful at all.
Additionally, you didn’t mention that using namespace aliases allows you to only specify the full type specification of one of the libraries, in case it is used much more often than the other.
But i’m already aware of all these solutions. I posted this issue to engage constructive conversation on how to improve our API surface and find a permanent solution, especially since async LINQ methods are very useful.
Since your solution doesn’t address my problem, please reopen the issue.
FYI, for EF Core 6.0, DbSet<T> will no longer be implementing IAsyncEnumerable<T>, removing the ambiguity and the need to call AsQueryable - see #24041 for more details and background.
I feel like chiming in after receiving hundreds of compile errors and reading this entire thread. This is coming from a developer with 18 years of .NET experience.
WTH? The reason I use .NET over Java or NodeJS is the complete stack is developed by one organization and feels cohesive. Why on earth should it be on US to go track down the .NET Core team and tell them they screwed up EF Core? Is there no testing or planning that takes place between the major component teams for .NET anymore? Who is in charge at Microsoft? Smit Patel’s attitude that this isn’t a big deal and no one should use both Linq and EF Core in the same file is also ridiculous - perhaps he’s also responsible for the decision that led to so much of our EF code requiring Linq to fill in all the gaps in the terrible EF 1.x and 2.x implementations that would take 20 minutes to run a query that normally could take a few seconds in classic .NET, where queries with simple operations had to be split into massive amounts of custom code just to get some resemblance of SQL query performance. “Oh, its not a big deal”…EF Core has become the “Oh its not a big deal” Joke. Every time there is an issue, lets just paper over it. You developers using our code, you work around our issues, we don’t have to change anything.
In a project with thousands of calls through EF Core, you are now saying we need to pollute hundreds if not thousands of lines of code with AsQueryable(), when the whole point of EF Core is IT IS QUERYABLE?!?!?
Seriously? Go complain to the .NET Core team? How about you guys get your act together and work as a cohesive organization and figure out a way to make your releases work properly? Otherwise what is the point in us continuing to develop on it over other modern server side frameworks like NodeJS? In an organization that has primarily switched to NodeJS, we had to fight like hell to go from .NET to .Net Core instead of Node… and all they’ve seen has been major performance issues from EF Core and us constantly having to work around YOUR issues.
I found out that this is worse than that, forget
System.Interactive.Linq. If you use bothSystem.LinqandMicrosoft.EntityFrameworkCore, you can’t even useWhereclause on theDbSet…https://github.com/aspnet/EntityFrameworkCore/issues/18220
I hope I am wrong and I messed up somewhere, because I can’t believe such a simple use case can be broken.
So for those stuck on
AsAsyncEnumerableconflict, you can use extern aliashttps://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias with the
::operator https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifierWhen I will fix it in my own code later, I will publish a clean solution here.
@ajcvickers @smitpatel I understand why you close this issue, but this is a big design mistake you did here. Those namespace conflicts will create countless of issues to noobs trying to figure out what is happening. Even me, coding in C# for more than 10 years non stop, I got confused…
Because you probably don’t want to make breaking change again, you will probably not change this decision, but still, ef did a huge design mistake.
You are making EF impossible to use with other libraries without using an obscure feature of the C# language that yourself don’t even know, and causing endless of conflict of
Select/Where.You should better remove interfaces from dbset, just coding classic method
AsQueryable()andAsAsyncEnumerable()within the type itself so it can’t possibly have conflicts.@NicolasDorier - It is a huge design mistake on IX-Async part to add their methods inside System.Linq namespace. Any library like EF which works with Queryable which can also be enumerated async.
Such methods if defined in BCL which everyone would be using by default make sense but not in external libraries.
Same, why is this issue closed?
@gandhis1 I actually see no reason why the DbSet’s should implement IAsyncEnumerable or even IEnumerable.
Maybe someone can explain this to me.
When I query a database (which is what Entity Framework is wrapping), I fully expect the query to go to the database and execute server side. If I want an IEnumerable, I can explicitly call something like ToListAsync().
When would I ever want to implicitly bring back the entire table to have client side operations run on it by mistake?
The simple solution is to break the users who for some odd reason are using the DbSet as an enumerable and force them to do the conversion, not to force actual Entity Framework users to put AsQueryable() in every single query. In a major reversal, EF Core 3 no longer plays pretend with IQueryable doing client side calls - this was a breaking change. The explicitness should be on casting to an IEnumerable, not in allowing IEnumerable by accident depending on which “usings” you have at the top of the file. And it would be completely understandable and acceptable for the EF Core team to break those use cases and force them to specifically bring back the whole database as a List before using Linq functions, as it fits with all other client-side breaks in 3.0.
I don’t even see this as a fault of the .NET Core team adding extension methods. While there should have been coordination (Anyone working on Linq or EF should know their methods could have the ability to conflict with each other, they are all identically named by design and have been for over 10 years!!), I don’t understand the purpose at all of making DbSet enumerable.
Did someone seriously think: “Here’s a good idea, I’m going to query this table, please wait for my 50 million records to come back before my operations get translated and ran”… ???
Ok so for those stuck, I ended up adding several extensions method at the root namespace of my project. This work because the compiler prefer extension methods in the current or parent namespace before looking the usings.
Please tell me this is not the only workaround, and I fucked up somewhere, how could something like that could have been missed?
I don’t know why you think that. I’m using async-LINQ to finish up the parts of queries that can’t be translated to SQL.
People use
AsEnumerable()on their query and then follow that up with LINQ — in fact, this is prescribed in your own documentation. Why are they not going to want to do the same in async scenarios?Exactly. It is not common to use both libraries in same project, where both method namespaces needs to be imported in same file where you are using raw DbSet to apply an async operation. Hence there is very little value to add a base class and not confuse other users which are using DbSet in normal way. Work-arounds posted above etc are good way to handle the corner case where customers run into it.
Solution A of https://github.com/dotnet/efcore/issues/18124#issuecomment-543817180 seems better to me.
With the current fix, we need to use
AsQueryableon every single query if we have a reference to System.Linq.Async !Whereas if
DbQuery<T>didn’t inherit fromIAsyncEnumerable<TEntity>, we would only have to useAsAsyncEnumerable()when needed. Sure it’s a breaking change, but IAsyncEnumerable is fairly new so I think it’s a good time to make a breaking change, before it rises in popularity, along with System.Linq.AsyncUnless I missed something?
All of those solutions are basically non-starters.
I worked around this by defining some extension methods:
DbSet<T>was nicer to use when it hadAsAsyncEnumerable()rather that implementingIAsyncEnumerable<T>.Ok, maybe not a great solution, I was just spitballing. I had forgotten IQueryable<T> had derived from IEnumerable<T>.
If anything, I feel strongly that this should never have happened.
An answer you gave a few screens up just irked me, you said its not a common case to have LINQ and EF in the same source… which suggests your unit testing may not cover many real world scenarios.
We have a large SQL database we inherited from way back in 2000 which we migrated to using EF Core in microservices. Many of our queries are computing mins or maxes or grabbing the first from a group, all things that in complex queries fail to get translated into SQL. Some of those queries were quite a cluster. We spent months hand optimizing EF queries all over the place, breaking them down into smaller queries & using LINQ to post-processes/combine/re-filter the EF results. We can’t be the only organization that ran into this. With EF Core 3 refusing to even run client side queries, you are explicitly forcing the two to co-exist - yet co-existing is incompatible.
So no, i’m not arguing I have the answer, or that there is a right answer now that it made it into 3.0. I’m more dissatisfied with the process that led to this, that our problem was discounted as unlikely to be an issue for people, and that it feels like both sides pass the buck even though you are the same organization, and many of us consider .NET and EF to be two parts of a single product that had a history of being well organized for 18 years. It feels more like while our complaints are being read, they aren’t really being heard.
We had held off upgrading for months because a single solution with over 80 projects is a real pain to upgrade. Yes, we have fixed it by calling AsQueryable() all over the place. And no, it doesn’t feel right to have done so. Its just disappointing.
I tested it even further, Issues arises only when applying async operator on DbSet. Further, if you want to use EF method, you can call AsQueryable on DbSet and call EF method afterwards and it will work fine. Like this
await db.Blogs.AsQueryable().FirstOrDefaultAsync();AsAsyncEnumerable, which we suggest as using work-around does not work either since it also has ambiguity. The root cause is, IX-async has put methods in
System.Linqnamespace. IAsyncEnumerable does not have methods defined in bcl which everyone can use. So multiple libraries have to define these methods. And since it being in System.Linq, it causes clashes on normal occasion too.Very broad generalization (or rather mis-interpretation) of what I said. I indicated that using EF Core and IX-Async in same project is not a common case. Using LINQ and EF Core in same project even same file works fine. The reason I indicated that IX-Async & EF Core is not commonly used together, is EF Core is the gateway to connect to database which is I/O sensitive and requires usage of async operations. IX-Async which works on IAsyncEnumerable does iterate async but process sync way only. From an user perspective database query should be translated to server for performance reason. That means neither Enumerable nor AsyncEnumerable extensions need to be called on a query used with EF Core. LINQ is still available to do other tasks which are not database query, e.g. Converting collection of DTO to collection of entity to be added to the database. Which is not async operation and works fine in EF. While mixing client side iterator operations with server side query is not invalid, it certainly is not the common case.
This issue arises from the fact that
IQueryable<T>derives fromIEnumerable<T>, due to symmetry, we had to manually addIAsyncEnumerable<T>interface on DbSet too. Elsefor eachover DbSet works but notawait for each. IfIQueryable<T>did not derive fromIEnumerable<T>we wouldn’t have addedIAsyncEnumerable<T>either. That means iterating naked DbSet would require calling a method in both cases making it consistent experience. But all these interfaces or even their extension methods are not in EF Core codebase. We have done what we could do in our source to provide a easy way to write the query. As I indicated earlier few times, https://github.com/dotnet/runtime is the right place for any discussion on this, they could remove IEnumerable from IQueryable base class or add IAsyncEnumerable to base class of IQueryable (in which case ambiguity would go away). They can also introduce a mechanism for providing priority of extension methods, which EF & IX-Async can utilize to define priorities to avoid ambiguity.DbSets are queryable to compose the query in exrepssion tree using LINQ. Queryable are implicitly enumerables. The statements you are making is outside the bounds of EF Core. You are asking to make a change that
IQueryable<T>does not derive fromIEnumerable<T>. Not only there are valid use cases for enumerating over DbSet for some users, even if you ignore that it is a big breaking change from how .NET has worked in last 10 years. If you really feel strongly that it is bad design then please file issue with your suggestion on https://github.com/dotnet/runtime repo. EF Core does not own those interfaces and cannot make any changes to them.(a) Revert 2795a00b613a5f4f23fca4ad1c53012d17adf7d3. This is a breaking change but prevents extension method conflicts between
IQueryable<T>andIAsyncEnumerable<T>.- Or -
(b) Add convenience methods to
DbSet<TEntity>that can be used to disambiguate extension method conflicts betweenIQueryable<TEntity>andIAsyncEnumerable<TEntity>.In (a), only
IQueryable<T>extension methods are applicable toDbSet<TEntity>and you useAsAsyncEnumerable()to get at theIAsyncEnumable<T>extension methods. This corresponds to usingAsEnumerable()to transition fromIQueryable<T>toIEnumerable<T>, which makes this solution discoverable.In (b), you explicitly choose whether you want to use either
IQueryable<T>orIAsyncEnumerable<T>extension methods. If there aren’t conflicting extension methods, you don’t have to use the convenience methods. If there are conflicting extension methods, and you don’t know to use the convenience methods, you get a compiler error about the ambiguous call, which makes this solution less discoverable.(b) can be implemented by the user as extension methods or even at the call site as an ugly cast, but if (a) isn’t acceptable then (b) may as well go in the box, as there are already less efficient and/or ambiguous extension methods that are applicable to
DbSet<TEntity>:AsQueryable(this IEnumerable<TElement>)AsAsyncEnumerable(this IQueryable<TSource>)AsAsyncEnumerable(this IAsyncEnumerable<TSource>)@shravan2x - Ambiguity in method resolution arises in compiler. There can be more ways to work-around the issue. I am not sure how can we improve API surface for some issue which is compiler issue rather than EF. We do not want to change Name FirstOrDefaultAsync or change interfaces implemented by DbSet. If you have any other idea, do tell us.
Reverting to .NET Core 2.2 because of this issue.
Note from triage: we will add the methods on DbSet as proposed above. This does not “fix” the entire problem, but should make it easier for people to use the two libraries together without needing to add their own extension methods. See #18622
@shravan2x - I totally agree with you on this. We would have also liked that. And alongside that, IQueryable to implement IAsyncEnumerable too just like IEnumerable. Then any ambiguity is gone the same way you do not have clash between IQueryable/IEnumerable methods. But till that becomes reality, right now due to IX-Async putting them in System.Linq namespace, not only EFCore any other ORM would be broken in similar way.
The way
MoreLinqhandles it is terrible and there is a whole thread of people complaining about it here:https://github.com/morelinq/MoreLINQ/issues/565
I like how
MoreLinqcan handle conflicts with other libraries: https://github.com/morelinq/MoreLINQ#usage I also think that this whole issue is caused largely by IX-Async decision to put their extensions inSystem.Linq.You are, of course, entirely correct. Removing the bogus using statement made the original code all work. I shall retract my ranty post and apologise profusely. :-s
Thank you!!
@Webreaper your error seems to indicate a conflict between EF Core’s Include and Include coming from System.Data.Entity, i.e. EF6 - so it doesn’t seem to be related with this issue. Check whether you intentionally have
usingfor both EF Core and EF6 in the same file.EF Core 2.2 used IX-Async package for async enumerables. In 3.0 EF Core does not depend on IX-Async rather uses IAsyncEnumerable from compiler directly.
Try the following and see it works. It worked successfully for me.
Instead of:
you just need:
@dguisinger there are data sources that can return records incrementally and beign able to await foreach them is actually prett sweet. EF isn’t just Sql Server. The IAsyncEnumerable is a legit feature.
My app targets .NET Framework 4.7.2 and references .NET Standard 2.0 library which provides database context and therefore uses EF Core 3.1. With this setting simple where expression fails:
var test = context.Accounts.Where(i => i.Active == true).ToList();generates error
On the other hand it compiles just fine in my another app targeting ASP .NET Core 3.1 which references the same library, so the issue arises in my case when combining .NET Framework with EF Core 3.1. Perhaps in .NET Core 3.1 there is no
System.Linq.AsyncEnumerable.Where()method or it doesn’t useIAsyncEnumerableinterface anymore.So, notice that in this case I don’t use async functionality at all, just plain simple Where() is not possible anymore.
Yes,
AsQueryable()fix works, but…it feels a bit ugly when you worked without it for many years, I understand that it is not EF Core fault but who we can talk to so they can properly fix it? Maybe we should open this issue in main .NET repo?
Cheers
@drdamour So far in my experimentation,
Context.DbSet.AsQueryable().[LinqExtensionMethod]seems to work. I don’t know if that helps you at all. I, also, figured that LINQ and EF were meant to be used together, and it’s surprising to find suggestions to the contrary in this thread.I ended up using @carlreinke’s solution (b) in my code, it looks good enough.
<tangential>
I see where you’re coming from @smitpatel, however IMHO these are core methods that could/should have been added to the built-in LINQ implementation to begin with. As we try to push users to write performant async code, synchronous LINQ methods complicate things. It forces them to litter their code with ugly
.Results orTask.WhenAll(...)s. Perhaps at some point in the future, C# will have them built-in and EF can find a clean way of letting users do both.</tangential>