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.