【问题标题】:.NET Core EF Primary Key Error on context.SaveChanges()context.SaveChanges() 上的 .NET Core EF 主键错误
【发布时间】:2019-03-25 06:21:35
【问题描述】:

我的Project 模型有一个<AppUsers> 的集合:

public class Project
    {
        public int ProjectID { get; set; }

        [Required(ErrorMessage = " Please enter a project name")]
        public string Name { get; set; }

        [Required(ErrorMessage = " Please enter a project description")]
        public string Description { get; set; }

        public virtual ICollection<AppUser> ProjectManagers { get; set; }
}

public class AppUser : IdentityUser
    {
       //just a placeholder for now until I add properties later
    }

在我的 EF 存储库中,当我尝试将任何用户分配给多个项目作为 ProjectManager 集合的一部分时出现错误(例如,我可以将它们分配给 Project1,但当我将它们分配给 Project2 时抛出异常)。

public void AddProjectManager(int projectID, AppUser user)
        {
            Project proj = context.Projects.Include(p => p.ProjectManagers).FirstOrDefault(p => p.ProjectID == projectID);
            if (!proj.ProjectManagers.Any(pm => pm.Id == user.Id))
            {
                AppUser appUser = identityContext.AspNetUsers.FirstOrDefault(p => p.Id == user.Id);
                if (appUser != null)
                {
                    proj.ProjectManagers.Add(appUser);
                    //ERROR OCCURS HERE WHEN I TRY TO SAVE
                    context.SaveChanges();
                }
            }
        }

我收到以下错误:

Violation of PRIMARY KEY constraint 'PK_AppUser'. Cannot insert duplicate key in object 'dbo.AppUser'. The duplicate key value is (xxx).

我尝试使用UserManager 方法,但得到相同的错误

【问题讨论】:

  • 一个AppUser可以分配给多个Projects吗?
  • @Priyank Panchal 这是我的意图,允许将一个用户分配到多个项目。不过,我可能错误地实施了这个想法

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


【解决方案1】:

通常这会导致 IEntityChangeTracker 的多个实例(请参阅:Why is my entity being referenced by multiple instances of IEntityChangeTracker?)但是我怀疑您的 identityContext 已关闭延迟加载代理,因此您会收到 PK 异常。

问题是您正在从一个上下文 (identityContext) 加载用户并尝试通过另一个上下文保存对它的引用。 (上下文)您想从相同的上下文中加载引用。应用程序上下文知道 AppUser,但它没有加载您与项目关联的实例,因为它是从不同的上下文加载的,因此它将其视为新的 AppUser。

解决方案是从context而不是identityContext加载AppUser

public void AddProjectManager(int projectID, AppUser user)
{
    Project proj = context.Projects.Include(p => p.ProjectManagers).FirstOrDefault(p => p.ProjectID == projectID);
    if (!proj.ProjectManagers.Any(pm => pm.Id == user.Id))
    {
         AppUser appUser = context.AspNetUsers.Single(p => p.Id == user.Id);
         proj.ProjectManagers.Add(appUser);
         context.SaveChanges();
    }
}

如果应用程序上下文中没有 AspNetUser 的 DbSet,则需要添加它。通常对于这样的事情,我不会将整个 AspNetUser 实体添加到应用程序上下文中,而是一个轻量级实体,其中包含我需要的详细信息(例如 ID 和名称),然后我的应用程序实体将引用这个轻量级实例(指出在同一张桌子上)以加快此关联的数据操作。

【讨论】:

  • 我在我的存储库中将public IQueryable&lt;AppUser&gt; AppUsers =&gt; context.AppUsers;AppUser appUser = context.AppUsers.Single(u =&gt; u.Id == user.Id); 结合使用,以使用与您建议的相同的上下文,但数据库中的AppUsers 表没有填充任何内容,导致sequence has no members 错误。我是否需要合并我的 AppIdentityDbContext.csApplicationDbContext.cs 类才能使用?
  • 那么 AppIdentityDbContext 映射到哪个表以供 App 用户使用?它是一个不同的数据库吗?如果它是一个单独的数据库,您可能需要设置复制以确保您的应用程序数据库具有用户。否则,您可以处理在应用数据库中找不到用户的位置并创建一个新用户,尽管这与您用于身份验证的事实来源不同步。
  • 目前,它们是同一个数据库,所以没关系。我最初使用了不同的DbContext 类,以防我想指向另一个数据库集AppUsers。但是,您无法解决的问题,我似乎在两个问题之间来回切换:当我将它们保持在相同的上下文中时,我遇到了一个问题,即只有一个项目从存储库返回;如果我将它们放在不同的上下文中,这似乎可以解决,但后来我得到了PK 问题(stackoverflow.com/questions/55291755/…
  • identityContext.AspNetUsers.FirstOrDefault(p =&gt; p.Id == user.Id); 是否返回了用户? (如果您在表中不包含用户记录的情况下进行身份验证,这似乎很奇怪。)预感听起来这两个上下文指向不同的数据库。
  • 是的,AspNetUsers 从默认的Identity 表中返回了一个用户。如果我试图将AppUser 表放入另一个数据库,那么它将不会返回任何内容(您已澄清的跨数据库问题)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
相关资源
最近更新 更多