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
### Steps to reproduce
1. Reference EFCore.
2. Reference System.Interactive.Async
``` C#
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
}
}
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
@shravan2x - Ways to deal with this
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync(Apples, x => x.NumSeeds == 5)
All of those solutions are basically non-starters.
I worked around this by defining some extension methods:
```C#
internal static class DbSetExtensions
{
public static IAsyncEnumerable
where T : class
{
return dbSet;
}
public static IQueryable<T> AsQueryable<T>(this DbSet<T> dbSet)
where T : class
{
return dbSet;
}
}
```
DbSet<T>
was nicer to use when it had AsAsyncEnumerable()
rather that implementing IAsyncEnumerable<T>
.
@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.
@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.
@smitpatel I notice that this issue only occurs when the Microsoft.EntityFrameworkCore.Sqlite
package version is upgraded from 2.2.6
to 3.0.0
. With 2.2.6
, both packages are installed and work fine. Do you know why that may be?
If you prefer, I can prepare a repro.
@carlreinke Your solution works great!
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.
I've updated my code to use @carlreinke 's solution. I'm fairly happy with it. Overall, you're right that this problem is hard to solve without changing the interfaces implemented by DbSet
.
However, (if I understand correctly), this problem occurs because DbSet
implements IEnumerable
. When iterating over it using IEnumerable
, all rows in the DB have to be fetched. However, fetching all rows is not a very common use case (at least for users like me). Perhaps we could add an alternative to DbSet
that doesn't implement IEnumerable
(maybe a base class)?
fetching all rows is not a very common use case
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.
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.
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?
I found out that this is worse than that, forget System.Interactive.Linq
. If you use both System.Linq
and Microsoft.EntityFrameworkCore
, you can't even use Where
clause on the DbSet
...
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.
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.
public static IAsyncEnumerable<TEntity> AsAsyncEnumerable<TEntity>(this Microsoft.EntityFrameworkCore.DbSet<TEntity> obj) where TEntity : class
{
return Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsAsyncEnumerable(obj);
}
public static IQueryable<TEntity> Where<TEntity>(this Microsoft.EntityFrameworkCore.DbSet<TEntity> obj, System.Linq.Expressions.Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return System.Linq.Queryable.Where(obj, predicate);
}
Please tell me this is not the only workaround, and I fucked up somewhere, how could something like that could have been missed?
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.Linq
namespace. 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.
After discussing again and re-investigating there doesn't seem to be anything we can do here. It would be a "normal" conflicting methods in two different namespaces problem, except that since, as @smitpatel says, IX-async decided to put their methods into System.Linq
which then invalidates many of the normal mechanisms provided by the compiler for dealing with such issues.
@smitpatel actually I remember I saw a way to remove ambiguity of namespace conflicts in C#.... trying to find again/
So for those stuck on AsAsyncEnumerable
conflict, you can use extern alias
https://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-qualifier
When 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()
and AsAsyncEnumerable()
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.
@NicolasDorier If there's something we can do in EF Core to make this better, then please suggest. We will consider it, even if it is a breaking change, based on how much help it would be and based on how much it would impact other experiences.
@ajcvickers this should never happen https://github.com/aspnet/EntityFrameworkCore/issues/18220 it happens whenever you reference namepace System.Linq and EF in the same file.
You can solve it by not implementing IQueryable
on DbSet
and instead put a AsQueryable non extension method. It would make clear to the user how to use it properly.
(a) Revert 2795a00b613a5f4f23fca4ad1c53012d17adf7d3. This is a breaking change but prevents extension method conflicts between IQueryable<T>
and IAsyncEnumerable<T>
.
- Or -
(b) Add convenience methods to DbSet<TEntity>
that can be used to disambiguate extension method conflicts between IQueryable<TEntity>
and IAsyncEnumerable<TEntity>
.
public abstract class DbSet<TEntity> : IQueryable<TEntity>, IAsyncEnumerable<TEntity>, ...
{
...
+ public IAsyncEnumerable<TEntity> AsAsyncEnumerable() => this;
+ public IQueryable<TEntity> AsQueryable() => this;
...
}
In (a), only IQueryable<T>
extension methods are applicable to DbSet<TEntity>
and you use AsAsyncEnumerable()
to get at the IAsyncEnumable<T>
extension methods. This corresponds to using AsEnumerable()
to transition from IQueryable<T>
to IEnumerable<T>
, which makes this solution discoverable.
In (b), you explicitly choose whether you want to use either IQueryable<T>
or IAsyncEnumerable<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>
:
@NicolasDorier
not implementing
IQueryable
onDbSet
This would break pretty much every EF application ever written, and also doesn't match how LINQ or IQueryable
are intended to be implemented/used.
@carlreinke
a) Is potentially possible as a breaking change in EF Core 5. However, it would have to help more people than it hurts, and it's not clear at this time that this is the case. However, we will keep monitoring feedback and consider it.
b) We will discuss this; it might be something we can do.
This would break pretty much every EF application ever written, and also doesn't match how LINQ or IQueryable are intended to be implemented/used.
I understand, but those application got already got broken because now there is conflicts if System.Linq is in the usings.
I just think this way would make it clearer for the user that DbSet
requires to use .AsQueryable
rather than scratching its head, and asking on github how to solve it.
Myself, I got confused and I code in C# since 2008.
Now I know we can use .AsQueryable()
, I am fine, but I expect those conflicts will generate most of your github issues.
I ended up using @carlreinke's solution (b) in my code, it looks good enough.
The root cause is, IX-async has put methods in System.Linq namespace. 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
.Result
s or Task.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.
IMHO these are core methods that could/should have been added to the built-in LINQ implementation to begin with.
@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.
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
In response to:
https://github.com/aspnet/EntityFrameworkCore/issues/18124#issuecomment-543549636
@smitpatel Can't you talk to the team to reconsider their implementation?
It is still new, breaking changes should not be a big impact yet. If you can't, do you know which repository here on github would be the right point?
Getting these errors because of implementing multiple interfaces, seems like a big flaw.
I'm going to join this party, too. I've upgraded my solution to .NET Core 3.0 and .NET Standard 2.1. We tried upgrading to EF 3.0 while we were at it, but aborted on account of the bug/breaking change I reported here. So meanwhile, we need to stay on EF Core 2.2.4. I couldn't get it to compile until I explicitly added a reference to System.Interactive.Async.4.0.0
. And none of the suggested workarounds above work for me...I'm getting the following exception:
System.TypeInitializationException : The type initializer for 'MyProject.DataAccess.MyDbContext' threw an exception.
----> System.TypeLoadException : Could not load type 'System.Collections.Generic.IAsyncEnumerable`1' from assembly 'System.Interactive.Async, Version=4.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'.
Any other suggested workarounds?
just ran into this myself when i introduced IAsyncEnumerable in my code and then brought in System.Linq.Async . Now anywhere i use System.Linq and Microsoft.EntityFrameworkCore i have issues.
It's VERY common to use IEnumerable System.Linq stuff in conjunction with Microsoft.EntityFrameworkCore right, don't we all do this?
Suppose someone removes using Microsoft.EntityFrameworkCore
and sticks to the IAsyncEnumerable stuff from System.Linq, they'd be in trouble now, right? Doesn't that mean every record from a set would be brought in? Or does that still get turned into an AST and compiled to SQL to pass to the db?
just ran into this myself when i introduced IAsyncEnumerable in my code and then brought in System.Linq.Async . Now anywhere i use System.Linq and Microsoft.EntityFrameworkCore i have issues.
It's VERY common to use IEnumerable System.Linq stuff in conjunction with Microsoft.EntityFrameworkCore right, don't we all do this?
Suppose someone removes
using Microsoft.EntityFrameworkCore
and sticks to the IAsyncEnumerable stuff from System.Linq, they'd be in trouble now, right? Doesn't that mean every record from a set would be brought in? Or does that still get turned into an AST and compiled to SQL to pass to the db?
@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.
@EvanWeeks adding .AsQueryable() gives the following error Include has been used on non entity queryable
Is there any official workaround for the initial issue?
@EvanWeeks adding .AsQueryable() gives the following error
Include has been used on non entity queryable
Is there any official workaround for the initial issue?
See https://github.com/dotnet/efcore/issues/16752. That specific error seems to have to do with using .Include()
after .Select()
or some other method that returns something other than an EF entity or IEnumerable
of entities. You have to use Include()
(andThenInclude()
)first. So, it looks like:
Context.DbSet.Include(dbs => dbs.Child).AsQueryable().[LinqExtensionMethod]
@EvanWeeks I can not do that change. I have complex query based on conditions.
Also is there any official workaround?
@pantonis
Can you post your query?
var query = (from order in context.Order.AsNoTracking()
where order.Timestamp.Date >= dateFrom.Date && order.Timestamp.Date <= dateTo.Date
select order);
if (somecondition)
var result = await query.Include(x => x.OrderType)
.Include(x => x.Address).ToListAsync();
The original query is quite bigger with more conditions. Just wanted to give an idea of my scenario
If you put the if first it should do what you want:
var baseQuery = context.Order;
if (somecondition)
baseQuery = baseQuery.Include(x => x.OrderType)
.ThenInclude(x => x.Address);
var query = (from order in baseQuery.AsNoTracking()
where order.Timestamp.Date >= dateFrom.Date && order.Timestamp.Date <= dateTo.Date
select order);
var result = await query.ToListAsync();
Also I tried to create these extension methods from one comment above
public static IAsyncEnumerable<TEntity> AsAsyncEnumerable<TEntity>(this Microsoft.EntityFrameworkCore.DbSet<TEntity> obj) where TEntity : class
{
return Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsAsyncEnumerable(obj);
}
public static IQueryable<TEntity> Where<TEntity>(this Microsoft.EntityFrameworkCore.DbSet<TEntity> obj, System.Linq.Expressions.Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return System.Linq.Queryable.Where(obj, predicate);
}
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
return System.Linq.Enumerable.Select(source, selector);
}
I have problems with ToListAsync() with the following error
'IEnumerable<Order>' does not contain a definition for 'ToListAsync' and no accessible extension method 'ToListAsync' accepting a first argument of type 'IEnumerable<Order>' could be found (are you missing a using directive or an assembly reference?)
see above.
I think your question is better for stackoverflow, so this issue can stay on topic.
@LunicLynx I still don't understand what is the workaround for this issue?
If you get the ambiguity add .AsQueryable()
. See last answer from @EvanWeeks
@LunicLynx thank you
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
error CS0121: The call is ambiguous between the following methods or properties: 'System.Linq.Queryable.Where
(System.Linq.IQueryable , System.Linq.Expressions.Expression >)' and 'System.Linq.AsyncEnumerable.Where (System.Collections.Generic.IAsyncEnumerable , System.Func )'
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 use IAsyncEnumerable
interface 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
@PsychoBoy11 - https://github.com/dotnet/runtime would be right place.
@PsychoBoy11 - https://github.com/dotnet/runtime would be right place.
Thanks sir. I'll check out if it is already mentioned somewhere. But I guess that since there is a plan to create bare "new" .NET 5, then they will probably consider fixing it there.
Solution A of https://github.com/dotnet/efcore/issues/18124#issuecomment-543817180 seems better to me.
With the current fix, we need to use AsQueryable
on every single query if we have a reference to System.Linq.Async !
Whereas if DbQuery<T>
didn't inherit from IAsyncEnumerable<TEntity>
, we would only have to use AsAsyncEnumerable()
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.Async
Unless I missed something?
The extern alias would have been a good work around so that we must always explicitly add the System.Linq namespace from System.Linq.Async package in the files we need to.
Unfortunately it doesn't look like PackageReference supports extern aliases :(
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.
@dguisinger i’m totally with you on this. Ever since @rowanmiller left the ef ship nobody seems to really love the product.
This is my really subjective view, i don't want to offend anyone.
@peter-dolkens - Which extension methods?
Sorry, ignore me, I misread something
@dguisinger You summarized my thoughts fairly well.
To Microsoft's credit, some of the smartest developers out there are working on the .NET ecosystem. It's incredibly unfortunate that a core design flaw now exists that may be impossible to undo.
I don't know the solution here, but I do think that raising additional attention to this may help convey the importance of this issue as we head towards .NET/EF Core 5.
Thinking aloud - perhaps C# needs some way to parameterize a method resolution order for extension methods? Not sure how it would work while still being decoupled...perhaps use the inheritance order as the priority along with some class-level attribute which instructs the compiler not to error on conflicts? And this would then get applied to DbSet
?
Anyway, I digress, this issue is for people smarter than me.
@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"... ???
@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.
I don't understand the purpose at all of making DbSet enumerable.
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 from IEnumerable<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.
Ok, maybe not a great solution, I was just spitballing. I had forgotten IQueryable
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.
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.
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 from IEnumerable<T>
, due to symmetry, we had to manually add IAsyncEnumerable<T>
interface on DbSet too. Else for each
over DbSet works but not await for each
. If IQueryable<T>
did not derive from IEnumerable<T>
we wouldn't have added IAsyncEnumerable<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.
Reverting to .NET Core 2.2 because of this issue.
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.
If you were using async interactive before, why not keep the reference in 3.0 (I know hindsight is 20/20, etc.) as they use the same async enumerable interface now as well.
If you were using async interactive before, why not keep the reference in 3.0
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.
Same, why is this issue closed?
@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 using
for both EF Core and EF6 in the same file.
@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
using
for both EF Core and EF6 in the same file.
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!!
That means neither Enumerable nor AsyncEnumerable extensions need to be called on a query used with EF Core.
That's really funny coming from the same team that recommends converting GroupJoin
and GroupBy
that EF Core can't handle by using AsEnumerable()
in the query.
It would be good to re-open this, at least for tracking purposes. The Reactive team considers this to be a design issue in EF Core:
I like how MoreLinq
can 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 in System.Linq
.
I like how
MoreLinq
can handle conflicts with other libraries:
The way MoreLinq
handles it is terrible and there is a whole thread of people complaining about it here:
Most helpful comment
@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.