Skip to content
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

[EF Core 8.x] - Primitive Collections doesn't work with ICollection, while querying data. #35502

Open
Morasiu opened this issue Jan 20, 2025 · 6 comments

Comments

@Morasiu
Copy link

Morasiu commented Jan 20, 2025

Bug description

Primitive Collections doesn't work with ICollection, while querying data.

According to this example it should work.

Note: IList, List and T[] works.

EFCoreICollectionBug.zip

Your code

// See https://aka.ms/new-console-template for more information

using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;

var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var context = new ApplicationDbContext(new DbContextOptionsBuilder<ApplicationDbContext>()
    .UseSqlite(connection)
    .Options);
context.Database.EnsureCreated();

var myDataWithList = new MyModelWithList
{
    MyEnums = new List<MyEnum> { MyEnum.Test1, MyEnum.Test2 }
};

context.MyModelWithLists.Add(myDataWithList);
await context.SaveChangesAsync();
context.ChangeTracker.Clear();

var dataWithList = await context.MyModelWithLists.FirstAsync(); // no error

// ERORR BELOW

var myData = new MyModel
{
    MyEnums = new List<MyEnum> { MyEnum.Test1, MyEnum.Test2 }
};

context.MyModels.Add(myData);
await context.SaveChangesAsync();
context.ChangeTracker.Clear();

var data = await context.MyModels.FirstAsync(); // error here


// CLASS DEFINITIONS
public enum MyEnum
{
    Test1,
    Test2,
    Test3
}

public class MyModel
{
    public Guid Id { get; set; }
    public ICollection<MyEnum> MyEnums { get; set; } = [];
}

public class MyModelWithList
{
    public Guid Id { get; set; }
    public List<MyEnum> MyEnums { get; set; } = [];
}

public sealed class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    public DbSet<MyModel> MyModels { get; set; } = null!;
    public DbSet<MyModelWithList> MyModelWithLists { get; set; } = null!;

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyModel>()
            .HasKey(x => x.Id);

        modelBuilder.Entity<MyModel>()
            .Property(x => x.MyEnums)
            .HasMaxLength(1024);
        
        modelBuilder.Entity<MyModelWithList>()
            .HasKey(x => x.Id);

        modelBuilder.Entity<MyModelWithList>()
            .Property(x => x.MyEnums)
            .HasMaxLength(1024);
    }
}

Stack traces

Unhandled exception. System.ArgumentException: Expression of type 'System.Collections.Generic.ICollection`1[EFCoreICollectionBug.MyEnum]' cannot be used for parameter of type 'System.Collections.Generic.IList`1[EFCoreICollectionBug.MyEnum]' of method 'System.Collections.Generic.IList`1[EFCoreICollectionBug.MyEnum] PopulateList[MyEnum](System.Collections.Generic.IList`1[EFCoreICollectionBug.MyEnum], System.Collections.Generic.IList`1[EFCoreICollectionBug.MyEnum])' (Parameter 'arg0')
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression arg0, Expression arg1)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityMaterializerSource.<AddInitializeExpressions>g__CreateMemberAssignment|14_0(Expression parameter, MemberInfo memberInfo, IPropertyBase property, Expression value)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityMaterializerSource.AddInitializeExpressions(HashSet`1 properties, ParameterBindingInfo bindingInfo, Expression instanceVariable, List`1 blockExpressions)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityMaterializerSource.CreateMaterializeExpression(List`1 blockExpressions, ParameterExpression instanceVariable, Expression constructorExpression, HashSet`1 properties, ParameterBindingInfo bindingInfo)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityMaterializerSource.CreateMaterializeExpression(EntityMaterializerSourceParameters parameters, Expression materializationContextExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.EntityMaterializerInjectingExpressionVisitor.CreateFullMaterializeExpression(ITypeBase concreteTypeBase, ValueTuple`4 materializeExpressionContext)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.EntityMaterializerInjectingExpressionVisitor.MaterializeEntity(StructuralTypeShaperExpression shaper, ParameterExpression materializationContextVariable, ParameterExpression concreteEntityTypeVariable, ParameterExpression instanceVariable, ParameterExpression entryVariable)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.EntityMaterializerInjectingExpressionVisitor.ProcessEntityShaper(StructuralTypeShaperExpression shaper)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.EntityMaterializerInjectingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.EntityMaterializerInjectingExpressionVisitor.Inject(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.InjectEntityMaterializers(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, IReadOnlyList`1& readerColumns, LambdaExpression& relatedDataLoaders, Int32& collectionId)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   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__DisplayClass12_0`1.<ExecuteAsync>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Program.<Main>$(String[] args) in D:\Projekty\EFCoreICollectionBug\EFCoreICollectionBug\Program.cs:line 38
   at Program.<Main>(String[] args)

Verbose output


EF Core version

8.0.6

Database provider

Microsoft.EntityFrameworkCore.Sqlite

Target framework

.Net 8

Operating system

Windows 11

IDE

Rider 2024

@AbdalkarimSaleh
Copy link

Hello Guys, if this issue is accepted I would like to take it, I am new here, any tips would be helpful

@Morasiu @roji

@Morasiu
Copy link
Author

Morasiu commented Jan 21, 2025

You have a zip in Issue which can help you with reproducing the Issue. Also somewhere in EF Core there is PopulateList method which is causing a problem.

@AbdalkarimSaleh
Copy link

Yeah I saw it, but I think the issue might be in VisitBinary in RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs that is calling PopulateList with an ICollection

@Morasiu
Copy link
Author

Morasiu commented Jan 21, 2025

Could be. But that's where my knowledge ends

@SamMonoRT SamMonoRT changed the title Primitive Collections doesn't work with ICollection, while querying data. [EF Core 8.x] - Primitive Collections doesn't work with ICollection, while querying data. Jan 21, 2025
@AbdalkarimSaleh
Copy link

Hi @SamMonoRT and @cincuranet

Can I work on this ? if you could allow me and guide me through it please

Kind regards

@SamMonoRT
Copy link
Member

Hi @SamMonoRT and @cincuranet

Can I work on this ? if you could allow me and guide me through it please

Kind regards

We welcome all community contributions. Please make a fix on EFcore main. Once you have a locally validated fix and PR ready for review, let us know and we can review and determine possibility of patching 8.0.x builds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants