【问题标题】:I am getting error quoted in the body when I add new user and try adding claim in the next line当我添加新用户并尝试在下一行添加声明时,我在正文中引用了错误
【发布时间】:2020-07-20 03:46:03
【问题描述】:

System.InvalidOperationException:实体类型“AppUser”上的“ConcurrencyStamp”属性是键的一部分,因此不能修改或标记为已修改。要使用标识外键更改现有实体的主体,首先删除依赖项并调用“SaveChanges”,然后将依赖项与新主体关联。'

一个简单的代码如下,

  1. 我正在创建一个新用户。
  2. 对于同一用户,我尝试添加声明。
  3. 我已经从 asp.net core(3.1.2) 添加了 IdentityUser 类

        var user = new AppUser() { UserName = userName, Email = emailAddress, FirstName = firstName, LastName = lastName };
        var passcode = GeneratePassword();
        var newUser = await userManager.CreateAsync(user, passcode);
    
        var addedClaim = await userManager.AddClaimAsync(user, new System.Security.Claims.Claim("usertype", "admin"));
    
        internal class AppUser : IdentityUser<int>, IRecord, IMPrimary {
         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]   
         [Column("RecordCode")] 
         public Guid RecId { get; set; } 
         public override int Id { get; set; } 
         public string FirstName { get; set; } 
         public string LastName { get; set; } 
        } 
    
        (below is coming from vb.net coded class)
    
        Public Interface Record 
        Property RecId As Guid 
        End Interface 
        Public Interface IMPrimary 
        Property Id As Integer 
        End Interface 
    

Asp.net 核心中的IdentityUser

public class IdentityUser<TKey> where TKey : IEquatable<TKey>
    {
        //
        // Summary:
        //     Initializes a new instance of Microsoft.AspNetCore.Identity.IdentityUser`1.
        public IdentityUser();
        //
        // Summary:
        //     Initializes a new instance of Microsoft.AspNetCore.Identity.IdentityUser`1.
        //
        // Parameters:
        //   userName:
        //     The user name.
        public IdentityUser(string userName);

        //
        // Summary:
        //     Gets or sets the date and time, in UTC, when any user lockout ends.
        //
        // Remarks:
        //     A value in the past means the user is not locked out.
        public virtual DateTimeOffset? LockoutEnd { get; set; }
        //
        // Summary:
        //     Gets or sets a flag indicating if two factor authentication is enabled for this
        //     user.
        [PersonalData]
        public virtual bool TwoFactorEnabled { get; set; }
        //
        // Summary:
        //     Gets or sets a flag indicating if a user has confirmed their telephone address.
        [PersonalData]
        public virtual bool PhoneNumberConfirmed { get; set; }
        //
        // Summary:
        //     Gets or sets a telephone number for the user.
        [ProtectedPersonalData]
        public virtual string PhoneNumber { get; set; }
        //
        // Summary:
        //     A random value that must change whenever a user is persisted to the store
        **public virtual string ConcurrencyStamp { get; set; }**
        //
        // Summary:
        //     A random value that must change whenever a users credentials change (password
        //     changed, login removed)
        public virtual string SecurityStamp { get; set; }
        //
        // Summary:
        //     Gets or sets a salted and hashed representation of the password for this user.
        public virtual string PasswordHash { get; set; }
        //
        // Summary:
        //     Gets or sets a flag indicating if a user has confirmed their email address.
        [PersonalData]
        public virtual bool EmailConfirmed { get; set; }
        //
        // Summary:
        //     Gets or sets the normalized email address for this user.
        public virtual string NormalizedEmail { get; set; }
        //
        // Summary:
        //     Gets or sets the email address for this user.
        [ProtectedPersonalData]
        public virtual string Email { get; set; }
        //
        // Summary:
        //     Gets or sets the normalized user name for this user.
        public virtual string NormalizedUserName { get; set; }
        //
        // Summary:
        //     Gets or sets the user name for this user.
        [ProtectedPersonalData]
        public virtual string UserName { get; set; }
        //
        // Summary:
        //     Gets or sets the primary key for this user.
        [PersonalData]
        public virtual TKey Id { get; set; }
        //
        // Summary:
        //     Gets or sets a flag indicating if the user could be locked out.
        public virtual bool LockoutEnabled { get; set; }
        //
        // Summary:
        //     Gets or sets the number of failed login attempts for the current user.
        public virtual int AccessFailedCount { get; set; }

        //
        // Summary:
        //     Returns the username for this user.
        public override string ToString();
    }

【问题讨论】:

  • 异常信息非常清楚。那么为什么ConcurrencyStamp 是密钥的一部分?我们看不到您如何配置 AppUser
  • 您好阿诺德,感谢您的回复,下面是用户类。对丑陋的阵型感到抱歉。内部类 AppUser : IdentityUser, IRecord, IMPrimary { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [Column("RecordCode")] public Guid RecId { get;放; } 公共覆盖 int Id { 获取;放; } 公共字符串名字 { 获取;放; } 公共字符串姓氏 { 获取;放; } } Public Interface Record Property RecId As Guid End Interface Public Interface IMPrimary Property Id As Integer End Interface
  • edit您的问题。 cmets 中的代码很难阅读。
  • 是的,很抱歉给您带来不便,代码已经添加到问题中。
  • 其实我并没有做任何特别的事情来继承/扩展这个类并使用它。但奇怪的是得到这个错误。

标签: c# asp.net-core entity-framework-core asp.net-identity


【解决方案1】:

我找到了错误的原因,所以我想与大家分享。我有一个重写的 OnModelCreating 方法。我主要用它来设置字符串值列的最大字符长度。对于某些内部目的逻辑,我将键设置为这些字符串基列。因此,当涉及到 IdentityUser 列时,它们也在无意中通过同一管道。下面代码中的 p.DeclaringEntityType.AddKey(p); 正在向 ConcurrencyStamp 添加密钥,这也是 Identity System 从未预料到的,因此它抛出了异常。

感谢Gert Arnold 为我提供的帮助。

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            if (modelBuilder == null)
                throw new NoNullAllowedException();
            var conventions = GetDbConventions();
            var props = GetPropertiesOfType(typeof(string));
            int maxCharacterLength = conventions.StringsColumnLength;
            foreach (var p in props)
            {
                if (p.GetMaxLength() < maxCharacterLength)
                    p.SetMaxLength(maxCharacterLength);
                p.IsNullable = false;
                p.DeclaringEntityType.AddKey(p);
            };  
       }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    相关资源
    最近更新 更多