-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Bug description
Bug description
I am trying to union two entity lists of the same type and selecting some data (without consulting the complex entity type property), but it throws an exception:
The data type json cannot be used as an operand to the UNION, INTERSECT or EXCEPT operators because it is not comparable.
Why
As suggested in the EfCore 10 release notes, we are migrating from owned entities (saved as json) to complex entity types. This results in several problems, and the bug described here is one of them.
The described scenario worked fine with owned entities.
Scenario
We try to union two sets of entities of the same type, grouping and selecting a calculation. The complex entity type is not consulted in the query filter or projection.
Your code
//entities
public partial class Project
{
public Guid Id { get; set; }
public Guid? ParentProjectId { get; set; }
[Ignore]
public virtual Project ParentProject { get; set; }
[Ignore]
public virtual ICollection<Project> ParentProjects { get; set; }
[Ignore]
public virtual ICollection<ProjectOrganisatie> ProjectOrganisaties { get; set; }
public IList<KolomMetadata> KolomMetadata { get; set; }
}
public partial class ProjectOrganisatie
{
public Guid Id { get; set; }
public Guid ProjectId { get; set; }
public bool IsInactief { get; set; }
[Ignore]
public virtual Project Project { get; set; }
}
//Mappings
public partial class ProjectMap
: IEntityTypeConfiguration<ClientName.ProjectName.Domain.Entities.Project>
{
public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<ClientName.ProjectName.Domain.Entities.Project> builder)
{
builder.ToTable("Project", "dbo");
builder.HasKey(t => t.Id);
builder.Property(t => t.ParentProjectId)
.HasColumnName("ParentProjectId")
.HasColumnType("uniqueidentifier");
builder.HasOne(t => t.ParentProject)
.WithMany(t => t.ParentProjects)
.HasForeignKey(d => d.ParentProjectId)
.HasConstraintName("FK_Project_Project");
builder.ComplexCollection(t => t.KolomMetadata, builder => builder.ToJson().Configure());
//Note: the Configure() method sets the property names of the KolomMetadata to camelCase
}
}
public partial class ProjectOrganisatieMap
: IEntityTypeConfiguration<ClientName.ProjectName.Domain.Entities.ProjectOrganisatie>
{
public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<ClientName.ProjectName.Domain.Entities.ProjectOrganisatie> builder)
{
builder.ToTable("ProjectOrganisatie", "dbo");
builder.HasKey(t => t.Id);
builder.Property(t => t.ProjectId)
.IsRequired()
.HasColumnName("ProjectId")
.HasColumnType("uniqueidentifier");
builder.Property(t => t.IsInactief)
.IsRequired()
.HasColumnName("IsInactief")
.HasColumnType("bit")
.HasDefaultValue(false);
builder.HasOne(t => t.Project)
.WithMany(t => t.ProjectOrganisaties)
.HasForeignKey(d => d.ProjectId)
.HasConstraintName("FK_ProjectOrganisatie_Project");
builder.ComplexCollection(t => t.KolomMetadata, builder => builder.ToJson().Configure());
}
}
//Scenario
Guid projectId = Guid.NewGuid();
Expression<Func<T, bool>> filter = p => p.Id == projectId;
Expression<Func<T, TOfProperty>> projection = p => p.ProjectOrganisaties.Union(p.ParentProjects.SelectMany(p2 => p2.ProjectOrganisaties))
.GroupBy(po => po.Project.ParentProjectId ?? po.ProjectId)
.Select(g => new
{
AantalInactief = g.Count(po => po.IsInactief)
})
.FirstOrDefault();
var query = dbContext.Set<Project>.AsQueryable()
.Where(filter)
.AsNoTracking() //read only query
.Select(projection);
var expression = query.Expression; //see below
var result = query.FirstOrDefaultAsync()(); //Throws exception
//Expression:
{[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].TagWith("Method: EntityFrameworkGenericRepositoryTests.FirstOrDefaultWithProjectionAsync_Should_Work_WithUnion() at line 61").Where(p => (p.Id == value(ClientName.ProjectName.Tests.RepositoryTests.EntityFrameworkGenericRepositoryTests+<>c__DisplayClass1_0).project.Id)).AsNoTracking().Select(p => p.ProjectOrganisaties.Union(p.ParentProjects.SelectMany(p2 => p2.ProjectOrganisaties)).GroupBy(po => (po.Project.ParentProjectId ?? po.ProjectId)).Select(g => new <>f__AnonymousType5`1(AantalInactief = g.Count(po => po.IsInactief))).FirstOrDefault())}
Arguments: Count = 2
CanReduce: false
DebugView: ".Call System.Linq.Queryable.Select(\r\n .Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking(.Call System.Linq.Queryable.Where(\r\n .Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.TagWith(\r\n .Extension<Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression>,\r\n \"Method: EntityFrameworkGenericRepositoryTests.FirstOrDefaultWithProjectionAsync_Should_Work_WithUnion() at line 61\")\r\n ,\r\n '(.Lambda #Lambda1<System.Func`2[ClientName.ProjectName.Domain.Entities.Project,System.Boolean]>))),\r\n '(.Lambda #Lambda2<System.Func`2[ClientName.ProjectName.Domain.Entities.Project,<>f__AnonymousType5`1[System.Int32]]>))\r\n\r\n.Lambda #Lambda1<System.Func`2[ClientName.ProjectName.Domain.Entities.Project,System.Boolean]>(ClientName.ProjectName.Domain.Entities.Project $p)\r\n{\r\n $p.Id == (.Constant<ClientName.ProjectName.Tests.RepositoryTests.EntityFrameworkGenericRepositoryTests+<>c__DisplayClass1_0>(Inte
rreg.ProjectName.Tests.RepositoryTests.Entit..."
Method: {System.Linq.IQueryable`1[<>f__AnonymousType5`1[System.Int32]] Select[Project,<>f__AnonymousType5`1](System.Linq.IQueryable`1[ClientName.ProjectName.Domain.Entities.Project], System.Linq.Expressions.Expression`1[System.Func`2[ClientName.ProjectName.Domain.Entities.Project,<>f__AnonymousType5`1[System.Int32]]])}
NodeType: Call
Object: null
Type: {Name = "IQueryable`1" FullName = "System.Linq.IQueryable`1[[<>f__AnonymousType5`1[[System.Int32, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], ClientName.ProjectName.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}Stack traces
Microsoft.Data.SqlClient.SqlException
HResult=0x80131904
Message=The data type json cannot be used as an operand to the UNION, INTERSECT or EXCEPT operators because it is not comparable.
Source=Core Microsoft SqlClient Data Provider
StackTrace:
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__195_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__22.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__22.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<InitializeReaderAsync>d__21.MoveNext()
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<MoveNextAsync>d__20.MoveNext()
at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__16`1.MoveNext()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__16`1.MoveNext()
at ClientName.ProjectName.Tests.RepositoryTests.EntityFrameworkGenericRepositoryTests.<FirstOrDefaultWithProjectionAsync_Should_Work_WithUnion>d__1.MoveNext() in C:\Projects\ClientName\ProjectName\ClientName.ProjectName.Tests\RepositoryTests\EntityFrameworkGenericRepositoryTests.cs:line 61
at Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution.TestMethodInfo.<ExecuteInternalAsync>d__55.MoveNext()
Verbose output
EF Core version
10.0.3
Database provider
Microsoft.EntityFrameworkCore.SqlServer
Target framework
.NET 10
Operating system
Windows 11
IDE
Visual Studio 2026 18.2.1