I am using Blazor Server, with EF Core and have an issue where EF is holding on to changes made to an entity (but not committed to the DB).
My Entity is created in this way in Program.cs
builder.Services.AddDbContext<RpContext>(options => options.UseSqlServer(config.GetConnectionString("RpCon")));
My Repository is added in Program.cs like this:
builder.Services.AddScoped<IUserRepository, UserRepository>();
The Repository Looks like this:
public class UserRepository : IUserRepository
{
private RpContext _entities;
public UserRepository(RpContext entities)
{
_entities = entities;
}
public User GetUserById(int id)
{
return _entities.User.Include(x => x.Profile).Where(x => x.Id == id).Where(x => x.Valid == true).FirstOrDefault();
}
}
public interface IUserRepository
{
User GetUserById(int id);
}
On my Blazor component I go to the database to get the user record like this:
public void GetUser(int userId)
{
UserDetails = null;
UserDetails = UserService.GetUserById(userId);
}
The page has an EditForm that is bound to UserDetails. Calling GetUser populates all fields correctly from the DB on first load of the page. If I then remove a value from any of the fields on the EditForm and then call the GetUser method again, tracking decides that it will use the entity as it stood on the page (without the values I removed) rather than going to the DB and getting a fresh copy (even though I have nulled it out previously).
I could use AsNoTracking but I want to track changes in the case where the user of the page decides to make a change and save it.
It feels like I have not got something quite right with the way I am using the context as this must be an extremely common use case (get a record, abandon, then reload without the abandoned changed).
Can anyone offer any pointers on where I might be going wrong?
RpContextto do everything. You need to use aDbContextFactory. Search "Blazor DbContextFactory" on here for other answers on the topic and read and understand this MS Docs article - learn.microsoft.com/en-us/ef/core/dbcontext-configurationFindat some point, which does return an already loaded object. That's not a bug when DbContext is used as intended - as a short-lived Unit-of-Work, disposed as soon as possible. A Unit-of-Work represents a single business transaction and its objects. The CRUD class though is registered as scoped, which means it remains alive for the entire user session.OnInitializedAsyncand dispose it inDispose. If it's shorter, you need to create it in a using block when needed. In both cases you can use a DbContextFactory to get instances from DI