context.SaveChanges() 上的 .NET Core EF 主键错误
.NET Core EF Primary Key Error on context.SaveChanges()
我的 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
方法,但得到了同样的错误
通常这会导致 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 和名称),然后我的应用程序实体将引用这个轻量级实例(指向同时table)来加速这个关联的数据操作。
我的 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
方法,但得到了同样的错误
通常这会导致 IEntityChangeTracker 的多个实例(参见:
问题在于您从一个上下文 (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 和名称),然后我的应用程序实体将引用这个轻量级实例(指向同时table)来加速这个关联的数据操作。