npgsql / efcore.pg

Entity Framework Core provider for PostgreSQL
PostgreSQL License
1.54k stars 226 forks source link

.NET 8 fails generating optimized model when using `List<TEnum>` #2976

Closed JustArchi closed 10 months ago

JustArchi commented 11 months ago

Minimum working repro:

[Table("test")]
public sealed class Asset {
    [Column]
    [Key]
    public int ID { get; set; }

    [Column]
    public List<EType> MatchableTypes { get; set; } = new();
}

public enum EType {
    Unknown,
    One,
    Two
}

public sealed class MyContext : DbContext {
    public DbSet<Asset> Assets => Set<Asset>();

    public MyContext(DbContextOptions<MyContext> options) : base(options) { }
}

This worked fine in EF Core 7 (.NET 7). After update to 8.0.0, it now gives error during dotnet ef dbcontext optimize:

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
   at Microsoft.CodeAnalysis.CSharp.SyntaxFactory.GetBinaryExpressionOperatorTokenKind(SyntaxKind kind)
   at Microsoft.CodeAnalysis.CSharp.SyntaxFactory.BinaryExpression(SyntaxKind kind, ExpressionSyntax left, ExpressionSyntax right)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitBinary(BinaryExpression binary)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitBlock(BlockExpression block)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.<TranslateConditional>g__TranslateConditionalStatement|35_0(ConditionalExpression conditional, <>c__DisplayClass35_0&)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateConditional(ConditionalExpression conditional, IdentifierNameSyntax lowerableAssignmentVariable)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitConditional(ConditionalExpression conditional)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitLoop(LoopExpression loop)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitBlock(BlockExpression block)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitLoop(LoopExpression loop)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitBlock(BlockExpression block)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitBlock(BlockExpression block)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateConditional(ConditionalExpression conditional, IdentifierNameSyntax lowerableAssignmentVariable)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitConditional(ConditionalExpression conditional)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitLambda[T](Expression`1 lambda)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateCore(Expression node, ISet`1 collectedNamespaces, Boolean statementContext)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateExpression(Expression node, ISet`1 collectedNamespaces)
   at Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.Expression(Expression node, ISet`1 collectedNamespaces)
   at Microsoft.EntityFrameworkCore.Design.Internal.CSharpRuntimeAnnotationCodeGenerator.Create(ValueConverter converter, CSharpRuntimeAnnotationCodeGeneratorParameters parameters, ICSharpHelper codeHelper)
   at Microsoft.EntityFrameworkCore.Design.Internal.RelationalCSharpRuntimeAnnotationCodeGenerator.Create(CoreTypeMapping typeMapping, CSharpRuntimeAnnotationCodeGeneratorParameters parameters, ValueComparer valueComparer, ValueComparer keyValueComparer, ValueComparer providerValueComparer)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal.NpgsqlCSharpRuntimeAnnotationCodeGenerator.Create(CoreTypeMapping typeMapping, CSharpRuntimeAnnotationCodeGeneratorParameters parameters, ValueComparer valueComparer, ValueComparer keyValueComparer, ValueComparer providerValueComparer)
   at Microsoft.EntityFrameworkCore.Design.Internal.ICSharpRuntimeAnnotationCodeGenerator.Create(CoreTypeMapping typeMapping, IProperty property, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.Create(IProperty property, String variableName, Dictionary`2 propertyVariables, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.Create(IProperty property, Dictionary`2 propertyVariables, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.CreateEntityType(IEntityType entityType, IndentedStringBuilder mainBuilder, IndentedStringBuilder methodBuilder, SortedSet`1 namespaces, String className, Boolean nullable)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.GenerateEntityType(IEntityType entityType, String namespace, String className, Boolean nullable)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.GenerateModel(IModel model, CompiledModelCodeGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CompiledModelScaffolder.ScaffoldModel(IModel model, String outputDir, CompiledModelCodeGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.Optimize(String outputDir, String modelNamespace, String contextTypeName)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OptimizeContextImpl(String outputDir, String modelNamespace, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OptimizeContext.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

/cc @roji

XieJJ99 commented 10 months ago

We're facing the same issue, the model works without pre-compiled model, but throws the "System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values." exception when trying to generate the optimized model. We attempted the following solutions without success:

  1. Marking the property as PrimitiveCollection
  2. Marking the property as PrimitiveCollection and then set the element conversion to int
roji commented 10 months ago

Can you please reopen this in the EF Core repo? This doesn't seem to be related to the Npgsql provider.

roji commented 10 months ago

Reopening since after fixing the EF-side issue (#32659), there's an issue on our side.

roji commented 10 months ago

Note that after these fixes, arrays with value converters are still incompatible with the compiled model - see https://github.com/dotnet/efcore/issues/32717.

JustArchi commented 8 months ago

@roji informational, it's probably intended if I understand your notes correctly, but for reference, this issue still applies to Npgsql.EntityFrameworkCore.PostgreSQL in version 8.0.2.

Not sure if you want to keep it closed or opened, up to you :+1:.

roji commented 8 months ago

@JustArchi yeah, that's expected - the problem is on the EF side with https://github.com/dotnet/efcore/issues/32717. I've opened #3104 to track this on our side - you can subscribe to that for updates etc.