Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error while adding user to role if AutoSaveChanges is false #63

Open
luwed opened this issue Apr 25, 2024 · 0 comments
Open

Error while adding user to role if AutoSaveChanges is false #63

luwed opened this issue Apr 25, 2024 · 0 comments

Comments

@luwed
Copy link

luwed commented Apr 25, 2024

Description

I'd like to disable AutoSaveChanges (I also changed key type to int), then create user, add it to role and save it to database. CreateAsync is succcessful. However when I try to add user to role I'm getting following error:

{
    "error": "The property 'User.Id' has a temporary value while attempting to change the entity's state to 'Unchanged'. Either set a permanent value explicitly, or ensure that the database is configured to generate values for this property."
}

Steps to Reproduce

  1. Change key type to int
  2. Create CustomUserStore which inherits from UserStore
  3. Disable AutoSaveChanges
  4. Run UserManager::CreateAsync
  5. Run UserManager::AddToRoleAsync

Actual result:
Error occurs:

{
    "error": "The property 'User.Id' has a temporary value while attempting to change the entity's state to 'Unchanged'. Either set a permanent value explicitly, or ensure that the database is configured to generate values for this property."
}

Expected result:
User added to role

Did you find any workaround?

Yes. Looking at the identity code I noticed that internally UpdateAsync is called after AddToRoleAsync. UpdateAsync calls Context.Attach on the user object. However user object is already tracked and modified so that the exception is thrown. I changed UpdateAsync in my custom user store to:

public override async Task<IdentityResult> UpdateAsync(User user, CancellationToken cancellationToken = default)
{
    if (AutoSaveChanges)
    {
        return await base.UpdateAsync(user, cancellationToken);
    }

    return IdentityResult.Success;
}

but then different error occurred:

{
    "error": "The value of 'UserRole.UserId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known."
}

Looking at DebugView.LongView I noticed that UserId in UserRole is different than Id in User so that relationship is wrong:

User {Id: -2147482647} Added
    Id: -2147482647 PK Temporary
    AccessFailedCount: 0
...


UserRole {UserId: -2147482646, RoleId: 1} Added
UserId: -2147482646 PK FK Temporary Unknown
RoleId: 1 PK FK    
...

Id which is set on User entity is 0 but Id tracked by EF is -2147482647. It seems that store does not recognize that Id has temporary value and treats it as new one. To "fix" relationship I assigned UserId in custom store:

protected override UserRole CreateUserRole(User user, Role role)
{
    var currentValueId = Context.Entry(user).Property(e => e.Id).CurrentValue;
    user.Id = currentValueId;

    return base.CreateUserRole(user, role);
}

Now it's working without exceptions. However it seems that it should be handled correctly by Identity. It seems that UpdateAsync is not needed to be called if AutoSaveChanges is false as the caller already decided to do it by himself. Entity should be also recognized as temporary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant