Skip to content

Query with value type complex property mapped to JSON fails #36552

@AndriySvyryd

Description

@AndriySvyryd

Message: 
System.ArgumentException : Argument types do not match

Stack Trace:
Expression.Constant(Object value, Type type)
JsonEntityMaterializerRewriter.g__ProcessFixup|13_1(IDictionary`2 fixupMap, <>c__DisplayClass13_0&) line 2065
JsonEntityMaterializerRewriter.VisitSwitch(SwitchExpression switchExpression) line 2048
ExpressionVisitor.VisitBinary(BinaryExpression node)
ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
ExpressionVisitor.VisitBlock(BlockExpression node)
ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
ExpressionVisitor.VisitBlock(BlockExpression node)
JsonEntityMaterializerRewriter.Rewrite(BlockExpression jsonEntityShaperMaterializer) line 1879
ShaperProcessingExpressionVisitor.CreateJsonShapers(ITypeBase structuralType, Boolean nullable, ParameterExpression jsonReaderDataParameter, Expression keyValuesParameter, Expression containerEntityExpression, IPropertyBase relationship) line 1723

Repro
[ConditionalFact]
public async Task Can_query_JSON_with_nested_collections()
{
    await using var testDatabase = await SqlServerTestStore.CreateInitializedAsync(DatabaseName);

    var options = Fixture.CreateOptions(testDatabase);
    await using (var context = new PersonContext(options))
    {
        context.Database.EnsureCreatedResiliently();

        var person = new Person() { Id = Guid.NewGuid(), Name = "John Doe" };
        var addresses = new List<Address>
        {
            new Address { Street = "123 Main St", City = "Anytown", State = "ST", ZipCode = "12345" },
            new Address { Street = "456 Oak Ave", City = "Another City", State = "ST", ZipCode = "67890" }
        };
        var phones = new List<Phone>
        {
            new Phone { Number = "555-1234", Type = PhoneType.Mobile },
            new Phone { Number = "555-5678", Type = PhoneType.Home }
        };
        person.Details = new PersonDetails
        {
            BirthDate = DateTime.Now.AddYears(-30),
            JobTitle = "Software Engineer",
            Phones = phones,
            Addresses = addresses
        };

        context.Add(person);

        context.SaveChanges();
    }

    await using (var context = new PersonContext(options))
    {
        var retrievedPerson = context.Persons.Single();
        Assert.NotNull(retrievedPerson);
        Assert.NotEmpty(retrievedPerson.Details.Phones);
        Assert.NotEmpty(retrievedPerson.Details.Addresses);
    }
}

public class Person
{
    public Guid Id { get; set; }
    public string Name { get; set; } = null!;
    public PersonDetails Details { get; set; }
}

public class Phone
{
    public PhoneType Type { get; set; } = PhoneType.Mobile;
    public string Number { get; set; } = null!;
}

public class Address
{
    public string Street { get; set; } = null!;
    public string City { get; set; } = null!;
    public string State { get; set; } = null!;
    public string ZipCode { get; set; } = null!;
}

public struct PersonDetails
{
    public PersonDetails()
    {
    }

    public DateTime BirthDate { get; set; }
    public string JobTitle { get; set; } = null!;
    public List<Phone> Phones { get; set; } = [];
    public List<Address> Addresses { get; set; } = [];
}

public enum PhoneType
{
    Mobile,
    Home,
    Work,
    Other
}

private class PersonContext(DbContextOptions options) : DbContext(options)
{
    public DbSet<Person> Persons { get; set; } = null!;
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>(b =>
        {
            b.ComplexProperty(p => p.Details, pb =>
            {
                pb.ToJson();
                pb.ComplexCollection(p => p.Addresses);
                pb.ComplexCollection(p => p.Phones);
            });
        });
    }
}

Metadata

Metadata

Assignees

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions