EF Core one to many relationships: ICollection or Hashset?

.net asp.net-core entity-framework entity-framework-core

Question

I am reading "Entity Framework Core in Action" by Jon P Smith. There it says:

enter image description here

Could you provide some examples when Hashet is a proper collection type? And why?

1
7
2/23/2019 10:03:02 AM

Accepted Answer

I personally use ICollection<T> for normal properties, just because its a well-known interface with minimal overheads, i.e. it is very slightly quicker to create an ICollection than a IList. You can of course use HashSet<T>, which is what EF Core uses, but I find HashSet's are a little harder to set than ICollection<T>, which takes a List<T>.

Note: I haven't looked at the speed of creation for any of these - I just do that because the book "Framework Design Guidelines" book shows that as best practice - see page 250.

The one place you have to use HashSet<T> if you are using uninitialized backing field collections - see code below:

private HashSet<Review> _reviews;
public IEnumerable<Review> Reviews => _reviews?.ToList();

UPDATE: With EF Core 3 the limitation of having to use HashSet<T> for uninitialized collections has been removed (see this issue). You can use ICollection<T>, List<T> etc.

IEnumerable<T> is a special case, because it turns a collection into a read-only version, due to IEnumerable not having a Add or Remove method. Backing fields plus IEnumerable<T> (see code above) allows you to "lock down" a collection relationship so that it can only be changed from inside the class (see my article Domain-Driven Design in EF Core).

When I use backing field collections I leave them uninitialized, so they need to be HashSet<T>. This allows me to detect when I forgot to use .Include when loading an entity, e.g. if I loaded a book without .Include(p => p.Reviews) and then accessed the Reviews property I would get a null reference exception. This is just a safe way of programming.

If you initialise a backing field collection then it can be ICollection etc., but I don't recommend initialising a backing field collection because it can cause problems if you forget the Include and then add a item to the collection. In that case EF Core deletes any existing reviews and replaces them with the the new one you added. From EF Core's point of view its doing what you said, but its most likely NOT what you intended.

12
10/24/2019 8:45:17 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow