JSON column translation fails when using .Union()
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- PR merge metrics
- PR metrics pending
Description
(Moved from https://github.com/npgsql/efcore.pg/issues/3042)
I'm using Npgsql.EntityFrameworkCore.PostgreSQL 8.0.0 and one table has a JSON column.
```
[Owned]
public class ThingMetadata
{
[...]
}
```
```
public class Thing
{
[...]
public ThingMetadata Metadata { get; set; }
[...]
}
```
```
public class ThingsDbContext: DbContext
{
public DbSet Things { get; set; }
[...]
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
[...]
modelBuilder.Entity().OwnsOne(
t => t.Metadata, ownedNavigationBuilder =>
{
ownedNavigationBuilder.ToJson();
});
[...]
}
}
```
Queries on this table fail if they return entities and use .Union():
```
using var db = new ThingsDbContext();
var query = db.Things
.Where(t => t.Id % 2 == 0)
.Union(
db.Things
.Where(t => t.Id % 3 == 0)
);
// query.Count() works
// db.Things.Where(t => t.Id % 2 == 0).ToList() works
return query.ToList()
```
```
Compiling query expression:
'DbSet()
.Where(t => t.Id % 2 == 0)
.Union(DbSet()
.Where(t => t.Id % 3 == 0))'
[...]
Including navigation: 'Thing.Metadata'.
Unhandled exception. System.InvalidOperationException: Translation of 'EF.Property(StructuralTypeShaperExpression:
[...]
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
, "Metadata")' failed. Either the query source is not an entity type, or the specified property does not exist on the entity type.
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateProjection(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.IncludeExpression.VisitChildren(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitExtension(Expression extensionExpression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
[...]
```
Minimal repro against sqlite by @WhatzGames:
```
using Microsoft.EntityFrameworkCore;
await using TestContext context = new();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
await context.ClassAs
.Where(x => x.Id % 2 == 0)
.Union(context.ClassAs.Where(x => x.Id % 3 == 0))
.ToArrayAsync();
public class TestContext : DbContext
{
public DbSet ClassAs => Set();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// optionsBuilder.UseNpgsql("Host=localhost;Database=efcore;Username=postgres;")
// .LogTo(Console.WriteLine);
optionsBuilder.UseSqlite("Data Source=efcore.db;");
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(builder =>
{
builder.OwnsOne(x => x.Test, navigationBuilder =>
{
//commenting out will result in a successful query
navigationBuilder.ToJson();
});
});
base.OnModelCreating(modelBuilder);
}
}
public class ClassA
{
public long Id { get; set; }
public required ClassB Test { get; set; }
}
public class ClassB
{
public Guid Id { get; set; }
}
```
Contributor guide
Assessment
This issue has not been assessed yet.