Home > database >  Why Entity Framework Core resets filled navigation property to null during AddRange only for first i
Why Entity Framework Core resets filled navigation property to null during AddRange only for first i

Time:12-08

I'm using the Asp Net Identity library and I've customized IdentityUser to have a custom navigation property called CompanyRole of type ApplicationRole here is rough structure bellow

public class ApplicationUser: IdentityUser
{
  ...
  public ApplicationRole CompanyRole { get; set }
}

public class ApplicationRole : IdentityRole
{
    public string Id{ get; set; }
    public string Name { get; set; }
}

Fragment of ApplicationUser model configuration


builder
    .HasOne(x => x.CompanyRole)
    .WithOne()
    .HasForeignKey<ApplicationUser>(au => au.CompanyRoleId)
    .OnDelete(DeleteBehavior.Restrict);

So when I try to add multiple users with existing roles like this


var viewerRole = await _rolesService.GetViewerRole() // it queries role from dbcontex behind the scene, so it should be tracked 

var usersToAdd = emails.Select(email => new ApplicationUser
    {
        FirstName = request.Name,
        Email = email,
        CompanyRole = viewerRole
    }
 )

_dbContext.Set<ApplicationUser>().AddRange(usersToAdd)
_dbContext.SaveChanges();

It complaints that cannot insert NULL in CompanyRoleId column, since it's a FK constraint.

The reason of this exception is that first user in a range gets CompanyRole as null, whereas others users are good. Why it's happening, since viewer role should have been tracked ?

I've tryed to play with Entities states, such as Added and Attach entity again - no luck

I've expected that all users are created with reference to existing ApplicationRole

BTW the workaround that worked, was if I split users adding one by one with slight changes and detach those immediately then it works, the drawback is that query per user...inefficient

var result = _dbContext.Set<ApplicationUser>().Add(user);
await _dbContext.SaveChangesAsync();
_dbContext.Entry(user).State = EntityState.Detached;

CodePudding user response:

The issue is that you are defining the relationship between user and company role as One to One. This means any 1 company role can be assigned to only one user. So as it tries to associate the role to each user, it would de-associate it from the previous.

What it looks like you want is a Many-to-one, many users can hold the same role. Adjust your mapping to:

builder
    .HasOne(x => x.CompanyRole)
    .Withmany()
    .HasForeignKey<ApplicationUser>(au => au.CompanyRoleId)
    .OnDelete(DeleteBehavior.Restrict);

... and you should be sorted.

  • Related