-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using non anonymous type inside outer/inner key selector of Join causes an error #25075
Comments
In order for join key selector to be translated to server as join predicate, join key needs to be either one of below
EF Core doesn't know how comparison of CompositeKey works and cannot translate above query. |
@smitpatel Thank you for your answer! 😄 Also there is no way to use my |
#25084 will allow specifying a value converter for it:
|
I could not make this (ie. creating arbitrary CompositeKey type and use it for join key-selector) work using EF Core 8. Coould you show a more detailed, working example? BUT, if you, @nemo048, are only looking to avoid anonymous types, such as me (for example to pass/return to/from method or generating expressions dynamically, etc.), tuples work great!
|
@balazsmeszegeto Could you elaborate or maybe enlight me about what I'm missing ? 🙂 |
@blemasle I use Npgsql.EntityFrameworkCore.PostgreSQL. But my understanding was that tuples are core features of efcore and work accross all providers. Maybe the static method |
IIRC tuples and ValueTuple.Create() specifically are only support in the PostgreSQL provider (and even there, only in very specific, retricted contexts). We do indeed plan to extend support but that's the current situation. @blemasle @balazsmeszegeto what's the reason for wanting to avoid anonymous types and using ValueTuple.Create instead? Regardless, specifically in the above example, that's a single-value tuple ( |
Thanks for the update. I also find the above example with single value odd, but having multiple values for a join is absolutely likely. One reason to avoid anonymous type is to utilize compiler support when creating expressions (see my SO link below) Still, I found this thread and in particular comment from @smitpatel #25075 (comment) was quite useful when faced the issue given in the title, it helped me to understand and resolve the issue. I've created a Q&A about this: https://stackoverflow.com/questions/78790038/entity-framework-core-using-non-anonymous-type-for-outer-inner-key-selector |
Looking at the SO, it seems that you basically prefer tuples over anonymous types because you're saying it's simpler to dynamically generate them in LINQ expression trees... I'm not sure why that's the case - both should be more or less similar. In any case, ValueTuple.Create() isn't something that's supported across all EF providers, in contrast to anonymous types. |
That explains why it's not working for me, I'm using SQL Server.
Long story short, I cannot use an anonymous type because the key expression must be supplied externally to the code calling It works when the join key is composed of only one value because in that case you can declare an |
Try using |
Not sure to understand how to convert it so it would be understandable by EF. Convert it to what ? The type is a composite, so it cannot be converted to a simple type that would be understood by the EF provider 🤔 |
Sorry I wasn't inspired to find a good simple use case, so names and properies are just here to made things easier to talk about but do not make much sense. What I try to achieve is essentially the Example codeusing Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Linq.Expressions;
var services = new ServiceCollection()
.AddDbContext<MyDbContext>(opts =>
{
opts.UseSqlite("Data Source=LocalDatabase.db");
});
var serviceProvider = services.BuildServiceProvider();
var dbContext = serviceProvider.GetRequiredService<MyDbContext>();
await dbContext.Database.EnsureCreatedAsync();
var addresses = await WorkingJoinAsync(dbContext);
var addresses2 = await NonWorkingJoin(dbContext, a => new JoinKey { Id = a.Id, Type = a.Type });
async Task<IReadOnlyCollection<Place>> WorkingJoinAsync(MyDbContext dbContext)
{
var places = await dbContext.Addresses
.Join(
dbContext.Places,
a => new { a.Id, a.Type },
p => new { p.Id, p.Type },
(a, p) => p)
.ToArrayAsync();
return places;
}
async Task<IReadOnlyCollection<Place>> NonWorkingJoin(MyDbContext dbContext, Expression<Func<Address, JoinKey>> exp)
{
var places = await dbContext.Addresses
.Join(
dbContext.Places,
exp,
p => new JoinKey { Id = p.Id, Type = p.Type },
(a, p) => p)
.ToArrayAsync();
return places;
}
class JoinKey
{
public int Id { get; set; }
public LocationType Type { get; set; }
}
internal class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> optionsBuilder)
: base(optionsBuilder)
{
}
public DbSet<Place> Places { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Place>();
modelBuilder
.Entity<Address>();
}
}
internal class Place
{
public int Id { get; set; }
public string Name { get; set; }
public LocationType Type { get; set; }
}
internal class Address
{
public int Id { get; set; }
public string Value { get; set; }
public LocationType Type { get; set; }
}
internal enum LocationType
{
Home,
Business
} |
This is all I got: https://learn.microsoft.com/en-us/ef/core/modeling/value-comparers#key-comparers We'd need to compare, but the samples from this page leads to converters. The best match is |
I've tried updating your sample:
Gives the same result. Tried to examine during runtime and observed that JoinKeyComparer never gots instantiated. Looking into the runtime model ( The following comment indicates that type mapping might be different than Property configuration:
|
I found a workaround using a template I left it in that public gist in case it could help anyone. |
Thanks! I'd still appreciate if someone with better knowledge about value comparers could enlighten us how should the above example ( |
Hello!
I have a problem with Join operation between some entities.
Assuming I have following entities:
And a
CompositeKey
class:Parent
andChild
entities are in myDbContext
. I want to join them as following:It works fine. But if I use non anonymous type
CompositeKey
in both key selectors it causes an error (The LINQ expression could not be translated)The error looks like this:
Could you please help me. Am I doing something wrong or there is a limitation for using non anonymous types inside Join key selectors?
EF Core version: 5.0.6
Database provider: Npgsql.EntityFrameworkCore.PostgreSQL
Target framework: .NET 5.0
Operating system: Windows 10 (20H2)
IDE: Jetbrains Rider 2021.1.3
The text was updated successfully, but these errors were encountered: