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.72k stars 3.17k forks source link

Attempting to use same navigation for two many-to-many relationships should result in last wins #29535

Open Mr-Technician opened 1 year ago

Mr-Technician commented 1 year ago

File a bug

Include your code

Adding an entity with a custom join table for its many to many relationship causes a NullReferenceException in this method of EF Core: https://github.com/dotnet/efcore/blob/main/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs#L750

I have included a minimal reproduction: https://github.com/Mr-Technician/EFCoreNullReferenceException

The error occurs in any 6.0.x version and is working in 5.0.x. Note that my actual project uses SQL Server, but the error appears regardless of database provider.

Include stack traces

Object reference not set to an instance of an object.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.InitialFixup(InternalEntityEntry entry, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.StateChanged(InternalEntityEntry entry, EntityState oldState, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.StateChanged(InternalEntityEntry entry, EntityState oldState, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.FireStateChanged(EntityState oldState)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   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 EFCoreNullReferenceException.Program.Main(String[] args) in C:\Users\rnielsen\source\repos\EFCoreNullReferenceException\EFCoreNullReferenceException\Program.cs:line 37

Include provider and version information

EF Core version: 6.0.0x Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer) Target framework: (e.g. .NET 6.0) Operating system: Windows IDE: Visual Studio 2022 17.4

milen-denev commented 1 year ago

I have the same exception throwned but since .NET 7

Mr-Technician commented 1 year ago

@milen-denev Was your code working .NET 6 and now no longer works in .NET 7? Or does it not run in either .NET 6 or .NET 7

milen-denev commented 1 year ago

@milen-denev Was your code working .NET 6 and now no longer works in .NET 7? Or does it not run in either .NET 6 or .NET 7

Sorry for my late reply. I was fixing this exact issue for in-production application. This that I thing happen, some dependensies where in Version 6 (ex. Microsoft.EntityFrameworkCore.SqlServer) and other where in version 7 and this broked many futures like Include() or in general any type of quering.

After I rolled back to .NET 6 and then again to .NET 7 (because it stopped working in both versions for this exact reason) and changed all dependensies from 6 to 7 back to 6 and again to 7 it got fixed.

Of course this is only assumption. But it's the most logical (to me) reason for this happening.

It may also be the same reason for you as well. Take a carefull look to the dependensies version of anything Microsoft.EntityFrameworkCore.* .

Mr-Technician commented 1 year ago

It may also be the same reason for you as well. Take a carefull look to the dependensies version of anything Microsoft.EntityFrameworkCore.* .

Unfortunately I don't think that is the case: https://github.com/Mr-Technician/EFCoreNullReferenceException/blob/master/EFCoreNullReferenceException/EFCoreNullReferenceException.csproj

ajcvickers commented 1 year ago

@Mr-Technician The User.Calls property:

public virtual ICollection<Call> Calls { get; set; } //we don't really need this property but it makes the many-to-many mapping happy

is used for more than one many-to-many relationship. This is not supported. In EF7, this property is not required and can be removed. If EF Core 6, the usual workaround is to use two private collection properties.

@AndriySvyryd We should probably catch this in model validation.

Mr-Technician commented 1 year ago

Adding a second collection fixed the issue. This project may stay on .NET 6 until the next LTS release next year, so having a non .NET7 workaround is good.

I agree though, this should be caught in model validation if possible.

ajcvickers commented 1 year ago

Note from triage: the first relationship should end up as unidirectional through introduction of a shadow navigation.