ASP.NET MVC5 EF6: Given multiplicity constraints, a corresponding 'User_AppUser_Target' must also in the 'Deleted' state. Repository Pattern

asp.net-identity-2 asp.net-mvc-5 c# entity-framework-6 repository-pattern

Question

I have an MVC5 project using Identity 2 and Entity Framework 6 and the repository pattern, that is redeveloping an old classic asp system. I started the project with Identity 1, after which in v2 they introduced that the ApplicationUser primary key can be anything, not just a GUID.

However, I have already mapped the ApplicationUser (AspNetUsers table) to my existing User table from the old project as a 1:1 relationship (as much as EF can). It is really a 1:1 which was necessary because my old table has many many fields.

When I try to delete a User, and it's associated ApplicationUser, I get the following error:

A relationship from the 'User_AppUser' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'User_AppUser_Target' must also in the 'Deleted' state.

Here is the Application User:

    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {                
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);             
            return userIdentity;
        }

        public virtual User User { get; set; }
    }

Here is the User

public class User : BaseModel
{        
    // The new identity system has a Guid as Id that is different to the UserId, So on the AspNetUser table there is new UserId field mapped.
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }    
    public virtual ApplicationUser AppUser { get; set; }      
    public string UserLogin { get { return AppUser.UserName; } }
    public string UserPass { get { return AppUser.PasswordHash; } }
    public string EmailAddress { get { return AppUser.Email; } }

    //.....ETC ....//
}

Here is the mapping:

modelBuilder.Entity<User>()                
            .HasRequired(e => e.AppUser)                
            .WithRequiredPrincipal(e => e.User)
            .Map(c=>c.MapKey("UserId"))
            .WillCascadeOnDelete(true);

Here is the applicationUser table (AspNetUser) I have a foreign key mapping to the User table:

  1. Id nvarchar(128)
  2. UserName varchart(256) etc..
  3. UserId int - maps to User Table: UserId int

And here is the deleting code:

[HttpPost, ValidateAntiForgeryToken]
public async Task<ActionResult> Delete([Bind(Include="Id")] UserSaveViewModel viewModel)
{            
    ApplicationUser appUser = UserManager.FindById(viewModel.Id);                        
    await UserManager.DeleteAsync(appUser);                        
    return RedirectToAction("Index", new { isUserDeleted = true });
}

I have also tried this instead of UserManager.DeleteAsync()

var user = appUser.User;
await _repository.DeleteAsync<User>(user); //using the repository pattern

But that gives this error:

The object cannot be deleted because it was not found in the ObjectStateManager.

How can I get this to cascade delete correctly?

1
1
1/7/2015 2:13:37 AM

Popular Answer

You cannot map a 1:1 relationship this way. The only way EF supports 1:1 mapping is with a shared primary key, which means both tables have to have the same key, and one has to be a foreign key to the other.

It's unfortunate, but it's a holdover from the time when EF did not support unique constraints, and you cannot have a 1:1 mapping without a shared primary key without using a unique constraint. When EF 6.1 added Unique index support, the internal logic was never updated to fully support 1:1 scenarios.

3
1/7/2015 3:46:04 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow