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

上下文上的.NET Core EF主键错误。SaveChanges()

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

    我的 Project model有一个 <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 方法,但得到相同的错误

    0 回复  |  直到 7 年前
        1
  •  1
  •   Steve Py    7 年前

    通常情况下,这会导致IEntityChangeTracker的多个实例(请参阅: Why is my entity being referenced by multiple instances of IEntityChangeTracker? )但是我怀疑你的identityContext关闭了延迟加载代理,所以你会得到PK异常。

    问题在于,您正在从一个上下文(identityContext)加载用户,并试图通过另一个上下文保存对该用户的引用。(上下文)要从同一上下文加载引用。应用程序上下文了解AppUser,但它没有加载与项目关联的实例,因为该实例是从不同的上下文加载的,所以它将其视为新的AppUser。

    解决方案是从 context 而不是 identityContext

    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和名称),然后我的应用程序实体将引用这个轻量级实例(指向同一个表),以加快此关联的数据操作。