You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF添加Employee时触发Projects主键约束冲突,如何解决?

问题:添加员工时触发主键重复异常

实体模型代码

public class Project
{
    public Guid ProjectId { get; set; }
    public string ProjectName { get; set; }
    public string ProjectInfo { get; set; }
    public Guid DepartMentId { get; set; }

    public ICollection<Employee> Employees { get; set; } = new List<Employee>();

    public Department Department { get; set; }
}

public class Employee
{
    public Guid EmployeeId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PayrollNumber { get; set; }
    public int Seniority { get; set; }
    [Column(TypeName = "decimal(10,2)")]
    public decimal Salary { get; set; }
    public int Rank { get; set; }
    public int Hours { get; set; }
    public ICollection<Project> Project { get; set; }
}

public class Department
{
    public Guid DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public string DepartmentInfo { get; set; }
    public int Rank { get; set; }
    public List<Project> Projects { get; set; } = new List<Project>();
}

添加员工的代码

public void AddEmployee(string fname, string lname, string payNum, int seniority, decimal salary, int hours, string projname)
{
    var proj = _projectController.GetProjects().Where(x => x.ProjectName == projname).SingleOrDefault();
    var projects = new List<Project>();
    projects.Add(proj);

    var emp = new Employee { EmployeeId = Guid.NewGuid(), FirstName = fname, LastName = lname, PayrollNumber = payNum, Seniority = seniority, Salary = salary, Hours = hours, Project = projects };

    _employeeController.AddEmployee(emp);
}

触发的异常信息

SqlException: Violation of PRIMARY KEY constraint 'PK_Projects'. Cannot insert duplicate key in object 'dbo.Projects'. The duplicate key value is (10bc054b-b9a7-47da-eb14-08dac1b7a7fe).
The statement has been terminated.

解决方案

问题根源

你从_projectController.GetProjects()获取的Project对象,处于当前DbContext未跟踪的状态。当你把这个未被跟踪的实体关联到新创建的Employee并执行SaveChanges()时,EF的变更追踪系统会误以为这是一个全新的Project实体,尝试向数据库插入一条主键重复的记录,从而触发主键约束异常。

具体解决方法

方法一:关联已存在实体的主键并附加到上下文

不需要传递完整的Project对象,只需要获取其主键,创建一个仅包含主键的Project实例,再附加到当前DbContext标记为已存在状态:

public void AddEmployee(string fname, string lname, string payNum, int seniority, decimal salary, int hours, string projname)
{
    // 仅获取项目主键
    var projId = _projectController.GetProjects()
                                   .Where(x => x.ProjectName == projname)
                                   .Select(x => x.ProjectId)
                                   .SingleOrDefault();

    if (projId == Guid.Empty)
    {
        // 处理项目不存在的异常情况
        return;
    }

    // 创建仅含主键的Project实例
    var proj = new Project { ProjectId = projId };
    // 附加到上下文,标记为未修改状态
    _dbContext.Attach(proj);

    var emp = new Employee 
    { 
        EmployeeId = Guid.NewGuid(), 
        FirstName = fname, 
        LastName = lname, 
        PayrollNumber = payNum, 
        Seniority = seniority, 
        Salary = salary, 
        Hours = hours, 
        Project = new List<Project> { proj } 
    };

    _employeeController.AddEmployee(emp);
}

方法二:确保获取的Project处于当前上下文跟踪状态

如果_projectController.GetProjects()返回的是未跟踪实体(比如使用了AsNoTracking()),可以直接在当前操作的DbContext中重新查询项目,确保实体被上下文跟踪:

public void AddEmployee(string fname, string lname, string payNum, int seniority, decimal salary, int hours, string projname)
{
    // 直接从当前DbContext查询项目,确保实体被跟踪
    var proj = _dbContext.Projects
                         .Where(x => x.ProjectName == projname)
                         .SingleOrDefault();

    if (proj == null)
    {
        // 处理项目不存在的情况
        return;
    }

    var emp = new Employee 
    { 
        EmployeeId = Guid.NewGuid(), 
        FirstName = fname, 
        LastName = lname, 
        PayrollNumber = payNum, 
        Seniority = seniority, 
        Salary = salary, 
        Hours = hours, 
        Project = new List<Project> { proj } 
    };

    _employeeController.AddEmployee(emp);
}

方法三:直接操作多对多中间表(可选)

如果EF自动生成了员工与项目的多对多中间表,你可以直接向中间表插入关联记录,无需通过实体导航属性:

// 假设中间表DbSet名为EmployeeProject
public void AddEmployee(string fname, string lname, string payNum, int seniority, decimal salary, int hours, string projname)
{
    var projId = _projectController.GetProjects()
                                   .Where(x => x.ProjectName == projname)
                                   .Select(x => x.ProjectId)
                                   .SingleOrDefault();

    if (projId == Guid.Empty)
    {
        return;
    }

    var emp = new Employee 
    { 
        EmployeeId = Guid.NewGuid(), 
        FirstName = fname, 
        LastName = lname, 
        PayrollNumber = payNum, 
        Seniority = seniority, 
        Salary = salary, 
        Hours = hours 
    };

    _employeeController.AddEmployee(emp);
    // 插入中间表记录
    _dbContext.EmployeeProject.Add(new EmployeeProject 
    { 
        EmployeeId = emp.EmployeeId, 
        ProjectId = projId 
    });
    _dbContext.SaveChanges();
}

内容的提问来源于stack exchange,提问作者Palamar66

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:25:41