代码之家  ›  专栏  ›  技术社区  ›  Daniel

实体类型“IdentityUserToken<string>”是用单个键属性定义的,但向“DbSet.Find”方法传递了3个值

  •  0
  • Daniel  · 技术社区  · 7 年前

    我不得不在创建的上下文类中手动添加Identity dbset,但上下文类中不包括我所希望的Identity表。我已经为我想要的ASPIdentity属性(角色、声明)创建了迁移,并测试了项目的注册/登录/管理方面。单击管理区域中的“双因素身份验证”选项卡时,出现以下错误:

    ArgumentException: Entity type 'IdentityUserToken<string>' is defined with a single key property, but 3 values were passed to the 'DbSet.Find' method.
    Microsoft.EntityFrameworkCore.Internal.EntityFinder<TEntity>.FindTracked(object[] keyValues, out IReadOnlyList<IProperty> keyProperties)
    Stack Query Cookies Headers 
    ArgumentException: Entity type 'IdentityUserToken<string>' is defined with a single key property, but 3 values were passed to the 'DbSet.Find' method.
    Microsoft.EntityFrameworkCore.Internal.EntityFinder<TEntity>.FindTracked(object[] keyValues, out IReadOnlyList<IProperty> keyProperties)
    Microsoft.EntityFrameworkCore.Internal.EntityFinder<TEntity>.FindAsync(object[] keyValues, CancellationToken cancellationToken)
    Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.FindAsync(object[] keyValues, CancellationToken cancellationToken)
    Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim>.FindTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
    Microsoft.AspNetCore.Identity.UserStoreBase<TUser, TKey, TUserClaim, TUserLogin, TUserToken>.GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
    Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal.TwoFactorAuthenticationModel<TUser>.OnGetAsync()
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.ExecutorFactory+GenericTaskHandlerMethod.Convert<T>(object taskAsObject)
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.ExecutorFactory+GenericTaskHandlerMethod.Execute(object receiver, object[] arguments)
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeHandlerMethodAsync()
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeNextPageFilterAsync()
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeInnerFilterAsync()
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
    Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
    Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
    Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
    Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
    

    中的服务代码 Startup.cs

    services.AddDefaultIdentity<User>()
        .AddRoles<IdentityRole>()
        .AddRoleManager<RoleManager<IdentityRole>>()
        .AddDefaultTokenProviders()
        .AddEntityFrameworkStores<MyContext>();
    

    public partial class MyContext : DbContext
    {
        public MyContext()
        {
        }
    
        public MyContext(DbContextOptions<MyContext> options)
            : base(options)
        {
        }
    
        public virtual DbSet<User> User { get; set; }
        public virtual DbSet<IdentityUserClaim<string>> IdentityUserClaim { get; set; }
        public virtual DbSet<IdentityUserToken<string>> IdentityUserToken { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<IdentityUserClaim<string>>().HasKey(p => new { p.Id });
    
            modelBuilder.Entity<IdentityUserToken<string>>().HasKey(p => new { p.UserId });
        }
    }
    

    我可以看到我需要包括更多的键,但找不到任何关于什么是关系的信息。我用ASPIdentity创建了一个空白的.NetCore MVC应用程序,并在中使用了相同的ASPIdentity配置 startup.cs 我一点也不知道,我应该用什么键,或者我应该如何构建 DbSet ?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Daniel    7 年前

    这篇文章对理解不同身份属性之间的关系有很大帮助: https://docs.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db

    DbContext OnModelCreating方法:

    modelBuilder.Entity<ApplicationUser>(b =>
    {
        // Each User can have many UserClaims
        b.HasMany(e => e.Claims)
            .WithOne(e => e.User)
            .HasForeignKey(uc => uc.UserId)
            .IsRequired();
    
        // Each User can have many UserLogins
        b.HasMany(e => e.Logins)
            .WithOne(e => e.User)
            .HasForeignKey(ul => ul.UserId)
            .IsRequired();
    
        // Each User can have many UserTokens
        b.HasMany(e => e.Tokens)
            .WithOne(e => e.User)
            .HasForeignKey(ut => ut.UserId)
            .IsRequired();
    
        // Each User can have many entries in the UserRole join table
        b.HasMany(e => e.UserRoles)
            .WithOne(e => e.User)
            .HasForeignKey(ur => ur.UserId)
            .IsRequired();
    });
    
    modelBuilder.Entity<ApplicationRole>(b =>
    {
        // Each Role can have many entries in the UserRole join table
        b.HasMany(e => e.UserRoles)
            .WithOne(e => e.Role)
            .HasForeignKey(ur => ur.RoleId)
            .IsRequired();
    
        // Each Role can have many associated RoleClaims
        b.HasMany(e => e.RoleClaims)
            .WithOne(e => e.Role)
            .HasForeignKey(rc => rc.RoleId)
            .IsRequired();
    });
    
    modelBuilder.Entity<ApplicationUserLogin>(b =>
    {
        b.HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId });
        b.ToTable("AspNetUserLogins");
    });
    
    modelBuilder.Entity<ApplicationUserRole>(b =>
    {
        b.HasKey(r => new { r.UserId, r.RoleId });
        b.ToTable("AspNetUserRoles");
    });
    
    modelBuilder.Entity<ApplicationUserToken>(b =>
    {
        b.HasKey(t => new { t.UserId, t.LoginProvider, t.Name });
        b.ToTable("AspNetUserTokens");
    });
    

    (我自己创造了 ApplicationUser 具有自定义属性的类)

        2
  •  1
  •   drim4591    5 年前

    这是个老问题,但万一有人需要这个。

    我认为你的问题不在于db模式。MVC应用程序的click事件中的某些内容最终使用了dbset。查找不正确;

    var tokenEntity = MyContext.UserTokens.Find(user.Id)
    

    相反,你可以只使用Linq;

    var tokenEntity = MyContext.UserTokens.FirstOrDefault(ut => ut.UserId == user.Id);
    

    using System.Linq