Skip to content

OriginalValue access on ComplexCollections not working for Entites in Added State #38486

Closed

Description

Bug description

The new ComplexCollection in EfCore 10 does not support gettings its original Value when the entity is in the "Added" State.
The code at

if (_containingEntry.EntityState == EntityState.Added)

shows that this decision seems to be intentional.

The result is that now OriginalValues.ToObject() is now broken for all entites that contain a complexCollection, making it not viable for our application as we rely on this feature for automated mechanisms through eg the library EntityFrameworkCore.Triggered

I let AI generate a sample code (and tested it myself) that demonstrates the problem and which can be found below

Your code

using Microsoft.EntityFrameworkCore;

// -------------------------------------------------------------------
// EF Core 10 – Bug repro: ComplexCollection does not support OriginalValues
// when the entity is in the 'Added' state, causing OriginalValues.ToObject()
// to throw InvalidOperationException.
// -------------------------------------------------------------------

using var db = new OrderContext();
db.Database.EnsureCreated();

var order = new Order
{
    Id = 1,
    Name = "Demo Order",
    LineItems =
    [
        new LineItem { Product = "Widget", Quantity = 2 },
        new LineItem { Product = "Gadget", Quantity = 5 },
    ]
};

db.Orders.Add(order);

var entry = db.Entry(order);
Console.WriteLine($"Entity state : {entry.State}");   // Added

// CurrentValues works fine.
Console.WriteLine($"CurrentValues[\"Name\"] : {entry.CurrentValues["Name"]}");

// OriginalValues on a plain scalar property also works for Added (EF copies it from current).
Console.WriteLine($"OriginalValues[\"Name\"] : {entry.OriginalValues["Name"]}");

// OriginalValues.ToObject() fails when a ComplexCollection is present on an Added entity.
// EF Core has no original-value snapshot for complex-collection elements yet, so it throws:
//   "The complex entry at the original ordinal '0' for the collection 'Order.LineItems'
//    cannot be accessed as the containing entry is in the added state."
Console.WriteLine();
Console.WriteLine("Calling entry.OriginalValues.ToObject() ...");
try
{
    var original = entry.OriginalValues.ToObject();   // <-- throws!
    Console.WriteLine($"Original object: {original}");
}
catch (InvalidOperationException ex)
{
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine($"[InvalidOperationException] {ex.Message}");
    Console.ResetColor();
}

Console.WriteLine("\nDone.");

// ── Model ──────────────────────────────────────────────────────────

public class Order
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public List<LineItem> LineItems { get; set; } = [];
}

public class LineItem
{
    public string Product { get; set; } = string.Empty;
    public int Quantity { get; set; }
}

// ── DbContext ──────────────────────────────────────────────────────

public class OrderContext : DbContext
{
    public DbSet<Order> Orders => Set<Order>();

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=demo.db");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // ComplexCollection requires ToJson() for relational providers.
        modelBuilder.Entity<Order>()
            .ComplexCollection(o => o.LineItems, b => b.ToJson());
    }
}

Stack traces

Unhandled exception. System.InvalidOperationException: The complex entry at the original ordinal '0' for the collection 'Order.LineItems' cannot be accessed as the containing entry is in the added state.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.InternalComplexCollectionEntry.GetEntry(Int32 ordinal, Boolean original)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntryBase.GetComplexCollectionOriginalEntry(IComplexProperty property, Int32 ordinal)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.OriginalPropertyValues.GetValueInternal(IInternalEntry entry, IPropertyBase property)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntryPropertyValues.Clone()
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntryPropertyValues.ToObject()
   at Program.<Main>$(String[] args) in C:\projects\Playground10\Playground10\Program.cs:line 40

Verbose output


EF Core version

10.0.9

Database provider

Microsoft.EntityFrameworkCore.Sqlite

Target framework

.Net 10

Operating system

No response

IDE

No response

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions