Question: why do you not allow `IImmutableList<T>` for collection navigational properties with backing fields?

Open
#21,176 5 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Needs clarification
Activity status
Stale
Tech stack
csharp
Domain
databases

Research direction

Start with the failing test TestSaveBookOneReviewAndReadOk in Test/UnitTests/TestDataLayer/Ch08_RelationshipBackingFields.cs at line 151. Read the relationship backing-field behavior and the RelationshipsSnapshot stack trace to determine why a HashSet is cast to IImmutableList. This issue is a question rather than a defined change, so a maintainer would need to clarify the expected behavior before implementation.

Written by the indexing model from the issue text.

Description

area-change-tracking area-o/c-mapping customer-reported

This is a question, rather than a request for a change!

I want to create entity classes where no properties can be changed outside the class (DDD-styled class). For instance:

public class Book
{
     private readonly List<Review> _reviews;
     public IEnumerable<Review> Reviews => _reviews.ToList();
     //... other properties left out
}

From my testing I know that collection navigational properties can use the following types -

  • IEnumerable<T>
  • IReadOnlyCollection<T>

I want to move away from using IEnumerable<T>, as it has (small) performance problems when you call it multiple times. I would like to use IImmutableList<T> as that sounds like a better type because it ensures that a) it takes a copy (AsReadOnly doesn't take a copy) and, b) makes parallel operations work better. But I get I use IImmutableList<T>.

   TestSaveBookOneReviewAndReadOk [0:00.749] Failed: System.InvalidCastException : Unable to cast object of type 'System.Collections.Generic.HashSet`1[DataLayer.EfClasses.Review]' to type 'System.Collections.Immutable.IImmutableList`1[DataLayer.EfClasses.Review]'.
System.InvalidCastException : Unable to cast object of type 'System.Collections.Generic.HashSet`1[DataLayer.EfClasses.Review]' to type 'System.Collections.Immutable.IImmutableList`1[DataLayer.EfClasses.Review]'.
   at lambda_method(Closure , InternalEntityEntry )
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.RelationshipsSnapshot..ctor(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.EnsureRelationshipSnapshot()
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntrySubscriber.SnapshotAndSubscribe(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.Add[TEntity](TEntity entity)
   at Test.UnitTests.TestDataLayer.Ch08_RelationshipBackingFields.TestSaveBookOneReviewAndReadOk() in C:\Users\JonPSmith\source\repos\EfCoreinAction-SecondEdition\Test\UnitTests\TestDataLayer\Ch08_RelationshipBackingFields.cs:line 151

IImmutableList<T> seems to tick all the boxes by supporting IEnumerable<T>, ICollection<T>, IList<T>. Also AsReadOnly() doesn't work with a HashSet, but ToImmutableList() does. so why does EF Core not support it? Is there something fundamental or just the way it is written?

NOTE: I have tried this on EF Core 3.1 and 5-preview4

Dominant language
C#
Stars
14.8k
Forks
3.4k
Avg merge
2d 5h
Merged PRs (30d)
134

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dotnet/efcore

All issues in dotnet/efcore

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.