dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.66k stars 3.15k forks source link

Rich collection support: Dictionary, Lookup, HashSet, etc. #2919

Open divega opened 9 years ago

divega commented 9 years ago

Based on feedback at https://github.com/aspnet/EntityFramework/issues/246#issuecomment-134423685.

sjb-sjb commented 5 years ago

During materialization, EF fixes up the navigation collections using standard interface properties e.g. ICollection<T>.Add. As mentioned in a comment in #12675 this is not very satisfactory because the ordering of elements is not preserved during a materialization -- a point that obviously only surfaces for ordered collections. Another way to state this is that the user would like to have Add with the normal semantics of "add at end" while redirecting EF to "add in sorted position"

In my experience there are other reasons why the application code may need different collection behavior than that which should be used during materialization. An example is the application code may need to lock an object (such as a DbContext or other object) when writing to the collection, while this locking may not be appropriate for EF materialization. Currently the only work-around for this, to my knowledge, is to have ICollection<T>.Add do something that is inconsistant with the other members of the collection and/or inconsistent with the normal definition of Add.

Based on this experience, I suggest that some thought be given to the current design in which EF uses the same interface to add entities during materialization as is used to expose the navigation in the entity. There is an analogy with the property access mode: there is a way to cause materialization to use direct field access, which is different from the way that the property is exposed in the entity class for use in the application. It might make sense to define a separate interface, INavigationCollection<T> with an Add method. A type derived from ICollection<T> would still be used to declare the navigation property, but if the instance object also implements INavigationCollection<T> then the INavigationCollection<T> interface would be used during EF operations such as materialization. This would cleanly solve the issue of separating EF's use and application code's use of the collection.

sjb-sjb commented 5 years ago

A further example on the challenges of locking and EF's use of collections. If the entity design requires locking the navigation collection then, in addition to the materialization/Add conflict noted above, a conflict occurs between locked enumeration and EF's use of the collection when entities are added to the context. When an entity is added to the context, EF will access the collection enumerator in order to patch up entity relationships. However, this may need to occur when the caller already is holding the lock for other reasons. These situations can be difficult to work around because the two alternatives -- either obtain the entity lock in the enumerator, or don't -- are unsatisfactory in many cases.

The INavigationCollection approach suggested earlier would address this example as well.

rbonomo commented 5 years ago

Please, somebody save me from ordering my child navigation properties after DB retrieval.

AndriySvyryd commented 1 year ago

This is the navigation counterpart to #2968