I have a simple One-To-Many relationship using EF6.
public abstract class AbstractModel
{
[Key]
public int Id { get; set; }
}
public class Parent : AbstractModel
{
[Required]
public string Name { get; set; } = string.Empty;
public IEnumerable<Child> Childs { get; set; } = new List<Child>();
}
public class Child: AbstractModel
{
[Required]
public string Name { get; set; } = string.Empty;
public Parent? Parent{ get; set; }
[Required]
public int ParentId { get; set; }
}
Additionally, I am using a generic repository/service approach to simplify DB access. All CRUD operations are working as expected, except for the update. I can update the Parents and Childs name without any problems, but if I add a Child to the Parents Childs list, changes are not written to the DB. The following code shows a unit test:
public async void Test_UpdateParent()
{
var parentService = new ParentService(this.DbContextFactory);
var parent = new Parent()
{
Name = "Test",
Childs = GenerateObjects<Child>(3, nameof(Child.Name)),
};
await parentService.Add(parent);
parent = await parentService.Get(parent.Id);
Assert.NotNull(parent);
parent.Name = "New Test";
var childList = parent.Childs.ToList();
childList.RemoveAt(2);
parent.Childs = childList;
Assert.Equal(true, await parentService.Update(parent));
parent = await parentService.Get(parent.Id);
Assert.NotNull(parent);
Assert.Equal("New Test", parent.Name);
Assert.Equal(2, parent.Childs);
ValidateObjects(parent.Childs.ToList(), 2, nameof(Child.Name));
}
If I run this test, the Assert Assert.Equal(2, parent.Childs); fails, because there are still 3 children.
public virtual async Task<bool> Update(TModel entity)
{
try
{
await using var context = await this.ContextFactory.CreateDbContextAsync();
context.Entry(entity).State = EntityState.Modified;
context.Update(entity);
await context.SaveChangesAsync();
return true;
}
catch (Exception)
{
await this.Refresh(entity);
return false;
}
}
I think the issue might be the fact that the context is created for each DB query. I have no way of testing this since it is required that the context is not disposed at any time. We ran into this issue, since our Blazor Server is fetching live data and needs to be up-to-date on each client at all times. This led to the problem that contexts, which were created within the constructor, went out of scope on the clients and made the application unusable.