When trying to attach/update an entity with multiple references to the same entity (and included with Include/ThenInclude), EF core throws an exception indicating the entity is already tracked.
For example:
I can work around this by using a new context to materialize the entity and then making the changes on that entity; or using context.Entry(rental).Reload(); however, is it possible to context.Attach or context.Update disconnected entities with multiple references to a same entity? Why or why not?
``` C#
class Program
{
static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
var ctx = host.Services.GetRequiredService
ctx.Database.Migrate();
//seed data
var seedUser = new User()
{
Id = "10",
UserName = "SeedUser"
};
var seedReservation = new ReservationSlot()
{
Id = "15",
User = seedUser
};
var seedRental = new Rental()
{
User = seedUser,
Id = "5",
Modified = DateTime.Now,
Reservations = new List<ReservationSlot>() { seedReservation }
};
ctx.Rentals.Add(seedRental);
ctx.SaveChanges();
ctx.Dispose();
var newCtx1 = host.Services.GetService<IServiceScopeFactory>().CreateScope().ServiceProvider.GetRequiredService<MyContext>();
//materialize disconnected entity
var rentals = newCtx1.Rentals
.Include(p => p.User)
.Include(p => p.Reservations)
.ThenInclude(p => p.User).AsNoTracking().ToList();
newCtx1.Dispose();
var rental = rentals.First();
//attach disconnected entity
var newCtx2 = host.Services.GetService<IServiceScopeFactory>().CreateScope().ServiceProvider.GetRequiredService<MyContext>();
//exception thrown for entity "User" being tracked more than once.
newCtx2.Attach(rental);
rental.Modified = DateTime.Now;
newCtx2.SaveChanges();
Console.ReadKey();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<MyContext>(o => o.UseSqlite("Data Source=blogging.db"));
});
}
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
public DbSet<Rental> Rentals { get; set; }
}
public class Rental
{
public string Id { get; set; }
public List<ReservationSlot> Reservations { get; set; }
public User User { get; set; }
public DateTime Modified { get; set; }
}
public class ReservationSlot
{
public string Id { get; set; }
public User User { get; set; }
}
public class User
{
public string Id { get; set; }
public string UserName { get; set; }
}
Alternatively, trying to seed the data with multiple references to the same User also raises the exception:
``` C#
//seed data
var seedUser = new User()
{
Id = "10",
UserName = "SeedUser"
};
var seedReservation1 = new ReservationSlot()
{
Id = "15",
User = seedUser
};
var seedReservation2 = new ReservationSlot()
{
Id = "16",
User = seedUser
};
var seedRental = new Rental()
{
User = seedUser,
Id = "5",
Modified = DateTime.Now,
Reservations = new List<ReservationSlot>() { seedReservation1, seedReservation2 }
};
ctx.Rentals.Add(seedRental); //exception thrown here for user already being tracked
ctx.SaveChanges();
ctx.Dispose();
Can EF core detect the same primary key and treat the entity as the same for tracking purposes?
EF Core version: 3.1.2
Database provider: npgsql
Target framework: .net core 3.1
Operating system: Win 10
IDE: vs 2019
Don't know if somehow this is also related to this issue:
https://github.com/dotnet/efcore/issues/19984
When we have two entities with the same Id in an object graph that we want to attach do EFCore.
In your case the User entity (in my case Author entity).
Don't know if somehow this is also related to this issue:
19984
When we have two entities with the same Id in an object graph that we want to attach do EFCore.
In your case the User entity (in my case Author entity).
Sounds like the same issue. I can provide both projects, one .net core 2.0 and one .net core 3.0 that produces this issue if needed. I think EF Core should be able to detect that the same primary key should map to the same entity.
@vflame
is it possible to context.Attach or context.Update disconnected entities with multiple references to a same entity? Why or why not?
This is not supported because in general resolution of conflicts between two or more different instances in the same graph is very ambiguous. Property values may be different, but more importantly, for anything other than a single entity with no relationships, the connections in the graph are also different.
See also #20124