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

InvalidCastException for EntityEntry.Reload() with complex type and TPH #33307

Closed
Wasserwecken opened this issue Mar 13, 2024 · 0 comments · Fixed by #33393
Closed

InvalidCastException for EntityEntry.Reload() with complex type and TPH #33307

Wasserwecken opened this issue Mar 13, 2024 · 0 comments · Fixed by #33393
Labels
area-dbcontext closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Milestone

Comments

@Wasserwecken
Copy link

Wasserwecken commented Mar 13, 2024

I tried to validate the fix of issue: #32701 This works so far! Thanks!

Unfortunatly, my complex type has more fields than in the provided example.
It looks like the some properties are mistaken in order by the Reload() / GetOriginalValueIndex() method?
All what I did to the previous example issue code was adding two more fields to the complex type.

image

(I did not evaluate if this comes down to the TPH combination, or if it is a general complex type problem)

Stacktrace

   bei Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer`1.Equals(Object left, Object right)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.AreEqual(Object value, Object otherValue, IProperty property)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetProperty(IPropertyBase propertyBase, Object value, Boolean isMaterialization, Boolean setModified, Boolean isCascadeDelete, CurrentValueType valueType)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetProperty(IPropertyBase propertyBase, Object value, Boolean isMaterialization, Boolean setModified, Boolean isCascadeDelete)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.set_Item(IPropertyBase propertyBase, Object value)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.CurrentPropertyValues.SetValueInternal(IProperty property, Object value)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntryPropertyValues.SetValues(PropertyValues propertyValues)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.Reload(PropertyValues storeValues)
   bei Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.Reload()
   bei ConsoleApp2.Program1.Test(String[] args) in C:\Users\ericd\Documents\Code\glaess\ConsoleApp1\Program1.cs: Zeile44
   bei ConsoleApp2.Program.Main(String[] args) in C:\Users\ericd\Documents\Code\glaess\ConsoleApp1\Program.cs: Zeile9

New Reproduction code

Im using .NET 8.0 with EFCore 8.0.3 and VS Studio 17.8.3.
Before running the code, migrations have to be added (Add-Migration Init)

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System.ComponentModel.DataAnnotations.Schema;

namespace ConsoleApp2
{
    internal static class Program1
    {
        public static void Test(string[] args)
        {
            using (var ctx = new CustomContext())
            {
                ctx.Database.Migrate();
                ctx.Add(new Supplier()
                {
                    Name = "FooBar",
                    Address = new()
                    {
                        Street = "WhereEver",
                        Altitude = Math.PI,
                        Number = 42,
                    }
                });
                ctx.SaveChanges();
            }

            using (var ctx = new CustomContext())
            {
                PropertyValues values = null!;
                var entry = ctx.Entry(ctx.Suppliers.First());

                // Order of Properties looks correct
                Console.WriteLine(nameof(entry.OriginalValues));
                values = entry.OriginalValues;
                foreach (var prop in values.Properties)
                    Console.WriteLine($"{prop.GetIndex()}: {prop.Name} -> {values[prop]}");

                Console.WriteLine(nameof(entry.GetDatabaseValues));
                values = entry.GetDatabaseValues()!;
                foreach (var prop in values.Properties)
                    Console.WriteLine($"{prop.GetIndex()}: {prop.Name} -> {values[prop]}");

                // This fails
                entry.Reload();
            }

            Console.WriteLine("Done!");
            Console.ReadLine();
        }
    }

    [ComplexType]
    public class Address
    {
        public required string Street { get; set; }
        public double? Altitude { get; set; }
        public int? Number { get; set; }
    }

    public abstract class Contact
    {
        public int Id { get; set; }
        public string? Discriminator { get; set; }
        public required string Name { get; set; }
        public required Address Address { get; set; }
    }

    public class Supplier : Contact
    {
        public string? Foo { get; set; }
    }

    public class Customer : Contact
    {
        public string? Bar { get; set; }
    }

    public class CustomContext : DbContext
    {
        public DbSet<Contact> Contacts { get; set; }
        public DbSet<Supplier> Suppliers { get; set; }
        public DbSet<Customer> Customers { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder builder)
            => builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=TestDb;Trusted_Connection=True");

        protected override void OnModelCreating(ModelBuilder builder)
            => builder.Entity<Contact>().HasDiscriminator(e => e.Discriminator);
    }
}
@ajcvickers ajcvickers self-assigned this Mar 13, 2024
@ajcvickers ajcvickers added type-bug closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. labels Mar 25, 2024
@ajcvickers ajcvickers added this to the 9.0.0 milestone Mar 25, 2024
ajcvickers added a commit that referenced this issue Mar 25, 2024
Fixes #33307

Property indexes are created such that properties of derived types are at the end--it has to be this way so that the indexes for properties on the base type remain the same for all derived types. However, when getting the flattened properties, we were returning them in a different order, such that properties with indexes for inherited type were returned in the middle of the list. This change instead returns the properties in the same order as their indexes.
ajcvickers added a commit that referenced this issue Mar 25, 2024
Fixes #33307

Property indexes are created such that properties of derived types are at the end--it has to be this way so that the indexes for properties on the base type remain the same for all derived types. However, when getting the flattened properties, we were returning them in a different order, such that properties with indexes for inherited type were returned in the middle of the list. This change instead returns the properties in the same order as their indexes.
ajcvickers added a commit that referenced this issue Mar 26, 2024
Fixes #33307

Property indexes are created such that properties of derived types are at the end--it has to be this way so that the indexes for properties on the base type remain the same for all derived types. However, when getting the flattened properties, we were returning them in a different order, such that properties with indexes for inherited type were returned in the middle of the list. This change instead returns the properties in the same order as their indexes.
@ajcvickers ajcvickers modified the milestones: 9.0.0, 9.0.0-preview3, 9.0.0-preview4 Mar 26, 2024
@ajcvickers ajcvickers removed their assignment Aug 31, 2024
@roji roji modified the milestones: 9.0.0-preview4, 9.0.0 Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-dbcontext closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants