繁体   English   中英

实体类型 &#39;IdentityUserToken<string> &#39; 使用单个键属性定义,但 3 个值已传递给 &#39;DbSet.Find&#39; 方法

[英]Entity type 'IdentityUserToken<string>' is defined with a single key property, but 3 values were passed to the 'DbSet.Find' method

我正在 .NetCore MVC 项目中工作,我不得不对现有的数据库进行逆向工程,但我真的很难让 ASPIdentity 正常运行。

我不得不在创建的 Context 类中手动添加我的 Identity DbSets,但它不包括我希望发生的 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>();

我的 onModelBuilding 代码(ASPidentity 特定代码):

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 应用程序,并在startup.cs使用了相同的 ASPIdentity 配置,但我不知道,我应该使用什么键或者我应该如何构建DbSet

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

我能够使用 Microsoft 文章中提供的关系信息和模板克服上述问题。

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类)

这是一个老问题,但以防万一其他人需要这个。

我不认为您的问题与 db 架构有关。 您的 MVC 应用程序的点击事件中的某些内容最终使用了 dbset.Find。在您的情况下;

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

相反,您可以使用 Linq;

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

也只需添加;

using System.Linq

暂无
暂无

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

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