繁体   English   中英

UserManager.AddToRole 不起作用 - 外键错误

[英]UserManager.AddToRole not working - Foreign Key error

在我的 ASP.NET MVC 应用程序中,我有一些代码应该相当简单:

UserManager.AddToRole(user.id, "Admin");

我刚收到这个错误...

INSERT 语句与 FOREIGN KEY 约束“FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId”冲突。 冲突发生在数据库“TestDatabase”、表“dbo.AspNetRoles”、“Id”列中。

我的 ASP.NET Identity Framework 是自定义的,因为一切都使用Guid作为键而不是intstring

任何想法是什么导致了这种情况?

编辑,根据用户评论...

用户类

public class User : IdentityUser<Guid, UserLogin, UserRole, UserClaim>
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override Guid Id
    {
        get { return base.Id; }
        set { base.Id = value; }
    }
}

角色类

public class Role : IdentityRole<Guid, UserRole>
{
    public const string Admininstrator = "Administrator";

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public new Guid Id { get; set; }
}

用户角色类

public class UserRole : IdentityUserRole<Guid>
{
}

internal class RoleManager : RoleManager<Role, Guid>
{
    public RoleManager(IRoleStore<Role, Guid> roleStore) : base(roleStore)
    {
    }

    public static RoleManager Create(IdentityFactoryOptions<RoleManager> options, IOwinContext context)
    {
        return new RoleManager(new RoleStore(context.Get<ApplicationDataContext>()));
    }
}

登录管理器类

internal class SignInManager : SignInManager<User, Guid>
{
    public SignInManager(UserManager userManager, IAuthenticationManager authenticationManager) : base(userManager, authenticationManager)
    {
    }

    public override Task<ClaimsIdentity> CreateUserIdentityAsync(User user)
    {
        return user.GenerateUserIdentityAsync((UserManager)UserManager);
    }

    public static SignInManager Create(IdentityFactoryOptions<SignInManager> options, IOwinContext context)
    {
        return new SignInManager(context.GetUserManager<UserManager>(), context.Authentication);
    }
}

用户管理器类

internal class UserManager : UserManager<User, Guid>
{
    public UserManager(IUserStore<User, Guid> store) : base(store)
    {
    }

    public static UserManager Create(IdentityFactoryOptions<UserManager> options, IOwinContext context)
    {
        var manager = new UserManager(new UserStore<User, Role, Guid, UserLogin, UserRole, UserClaim>(context.Get<ApplicationDataContext>()));
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<User, Guid>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        // Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;

        // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
        // You can write your own provider and plug it in here.
        manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<User, Guid>
        {
            MessageFormat = "Your security code is {0}"
        });
        manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<User, Guid>
        {
            Subject = "Security Code",
            BodyFormat = "Your security code is {0}"
        });
        manager.EmailService = new EmailService();
        manager.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<User, Guid>(dataProtectionProvider.Create("ASP.NET Identity"));
        }

        return manager;
    }
}

RoleStore 类

internal class RoleStore : RoleStore<Role, Guid, UserRole>
{
    public RoleStore(DbContext context) : base(context)
    {
    }
}

更新1:

罪魁祸首就在这里……

public class Role : IdentityRole<Guid, UserRole>
{
    public const string Admininstrator = "Administrator";

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public new Guid Id { get; set; }
}

……特别……

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new Guid Id { get; set; }

我用脏的 hack替换了它,它有效

public Role()
{
    Id = Guid.NewGuid();
}

如果这对任何人有帮助吗? 我个人宁愿不要使用肮脏的黑客!

替换

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new Guid Id { get; set; }

使用流畅的api。 在自定义IdentityDbContext类中添加

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
       base.OnModelCreating(modelBuilder);
       // identity
       modelBuilder.Entity<User>().Property(r=>r.Id)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
       modelBuilder.Entity<Role>().Property(r=>r.Id)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}

在上次更新之后,现在很清楚了 - 我猜是在创建表之后添加了DatabaseGenerated(DatabaseGeneratedOption.Identity) 而实际的数据库并不知道它需要生成主键,它期望客户端提供主键。

如果您在ApplicationRoles表(或您拥有的任何相应表名称)上查看 SSMS(右键单击表 - >“设计”并查看字段Id上的“默认值或绑定”,它将为空。但它应该说newid() : 默认值或绑定设置为 <code>newid()</code>

迁移并不总是会接受这种变化,你最终会遇到像你这样的错误。 对此的解决方案是尝试添加另一个 EF 迁移,它应该为您提供如下信息:

AlterColumn("dbo.ApplicationRoles", "Id", c => c.Guid(nullable: false, defaultValueSql: "newid()"));

虽然这并不总是有效。 有时我不得不完全删除并重新创建表,以便 EF 获取我希望 DB 为我生成 ID 的信息。

或者(我认为这是一个更好的解决方案DatabaseGenerated(DatabaseGeneratedOption.Identity)Id字段上方的属性中删除DatabaseGenerated(DatabaseGeneratedOption.Identity)并保留

public Role()
{
    Id = Guid.NewGuid();
}

这允许您在数据库中创建记录之前自己定义键。 如果您使用 CQRS 架构,这会更好。 但是 EF 删除属性可能会很有趣,并会要求进行另一次迁移。

这可能对自定义默认 IdentityUser 的其他人有用

不过,我在不同的配置下遇到了相同的错误。 实际问题是AddToRoleAsync()方法从默认IdentityUser指向Id而不是我的自定义用户,这当然是从IdentityUser<int>继承的,将 PK 作为UserId

AddToRoleAsync()方法从默认IdentityUser指向Id ,但我们为自定义用户使用不同的主键时,我们在IdentityUserId列中有0 这就是它由于引用完整性而引发错误的原因。 这种参照完整性要求外键也必须存在于父表中。 在这种情况下,父表User没有主键值0

因此,我只是删除了我的UserId并使用了来自IdentityUser的现有Id 因为我并不期待修改UserManager类。

祝你好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM