Ef Core 正在保存 Employee 实体 Throw 无法将值 NULL 插入列“” table Job Title

Ef Core saving Employee entity Throw Cannot insert the value NULL into column ' ' table Job Title

在我的应用程序中,我使用了工作单元和存储库模式以及自动映射器
这是 employeeDto

public partial class EmployeeDto
{
public string IdEmployee { get; set; }
public string FirstNameEmployee { get; set; }
public string LastNameEmployee { get; set; }
public int? FkDepartment { get; set; }
public int? FkJobTitle { get; set; }
public string Department { get; set; }
public string JobTitle { get; set; }

public virtual DepartmentDto FkDepartmentNavigationDto { get; set; }
public virtual JobTitleDto FkJobTitleNavigationDto { get; set; }
}

而这个 JobTitleDto

public partial class JobTitleDto
 {
    public JobTitleDto()
    {
        EmployeesDto = new HashSet<EmployeeDto>();
    }

    public int IdJobTitle { get; set; }
    public string NameJobTitle { get; set; }

    public virtual ICollection<EmployeeDto> EmployeesDto { get; set; }
 }

这是 EF Core 生成的代码

    public void Configure(EntityTypeBuilder<Employee> entity)
    {
        entity.Property(e => e.FkDepartment).HasColumnName("FK_Department");

        entity.Property(e => e.FkJobTitle).HasColumnName("FK_JobTitle");

        entity.HasOne(d => d.FkDepartmentNavigation)
            .WithMany(p => p.Employees)
            .HasForeignKey(d => d.FkDepartment)
            .HasConstraintName("FK_Employee_Department");

        entity.HasOne(d => d.FkJobTitleNavigation)
            .WithMany(p => p.Employees)
            .HasForeignKey(d => d.FkJobTitle)
            .HasConstraintName("FK_Employee_JobTitle"); 

        OnConfigurePartial(entity);
    }

在 JobTitleService 中,我得到所有这样的 JobTitle

 public class JobTitleService: BaseService
{
    public JobTitleService(IUnitOfWork unitOfWork, IMapper mapper):base(unitOfWork, mapper)
    {

    }
    public async Task<IEnumerable<JobTitleDto>> GetAllJobTitlesAsync()
    {
        var jobTitle = await unitOfWork.JobTitles.GetAllAsync();
        return mapper.Map<IEnumerable<JobTitleDto>>(jobTitle);
    }
}

这就是我获得和添加员工的方式

public EmployeeService(IUnitOfWork unitOfWork, IMapper mapper):base(unitOfWork, mapper)
{

}
public async Task<IEnumerable<EmployeeDto>> GetAllEmployeesDetailsAsync()
{
    var employee = await unitOfWork.Employees.GetAllIncluding(
                    emp => emp.FkCountryNavigation,
                    emp => emp.FkDepartmentNavigation,
                    emp => emp.FkGenderNavigation,
                    emp => emp.FkJobTitleNavigation,
                    emp => emp.FkMaritalStatusNavigation,
                    emp => emp.FkProvincesNavigation,
                    emp => emp.FkTownNavigation);
    return mapper.Map<IEnumerable<EmployeeDto>>(employee);
}
public async Task<bool> InsertEmployeeAsync(EmployeeDto employeeDto)
{
    var employee = mapper.Map<Employee>(employeeDto);
    return await unitOfWork.Employees.AddAsync(employee);
}

这是员工表格背后的代码

    private BindingSource listEmployeeDto = new();
private readonly EmployeeService employeeService;
private readonly DepartmentService departmentService;
private readonly JobTitleService jobTitleService;

public FrmEmployee(EmployeeService employeeService, 
                   DepartmentService departmentService,
                   JobTitleService jobTitleService)
{
    InitializeComponent();
    this.employeeService = employeeService;
    this.departmentService = departmentService;
    this.jobTitleService = jobTitleService;
}
 private async void btnSave_Click(object sender, EventArgs e)
{
    var employeeDto = listEmployeeDto.Current as EmployeeDto;
    await employeeService.InsertEmployeeAsync(employeeDto);
    await employeeService.CompleteAsync();
}
private async Task LoadDataAsync()
{
    listEmployeeDto.DataSource = await employeeService.GetAllEmployeesDetailsAsync();
    gridControl1.DataSource = listEmployeeDto;

    cmbJobtitle.Properties.DataSource = await jobTitleService.GetAllJobTitlesAsync();
    cmbJobtitle.Properties.DisplayMember = "NameJobTitle";
    cmbJobtitle.Properties.ValueMember = "IdJobTitle";

    cmbDepartment.Properties.DataSource = await departmentService.GetAllDepartmentsAsync();
    cmbDepartment.Properties.DisplayMember = "NameDepartment";
    cmbDepartment.Properties.ValueMember = "IdDepartment";
}
private void BindingControls()
{
    var employeeDto = listEmployeeDto.Current as EmployeeDto;
    txtUserID.DataBindings.Add(new Binding("EditValue", listEmployeeDto, nameof(employeeDto.IdEmployee)));
    txtFirstName.DataBindings.Add(new Binding("EditValue", listEmployeeDto, nameof(employeeDto.FirstNameEmployee)));
    txtLastName.DataBindings.Add(new Binding("EditValue", listEmployeeDto, nameof(employeeDto.LastNameEmployee)));
    cmbJobtitle.DataBindings.Add(new Binding("EditValue", listEmployeeDto, nameof(employeeDto.FkJobTitle), true, DataSourceUpdateMode.OnPropertyChanged));
    cmbDepartment.DataBindings.Add(new Binding("EditValue", listEmployeeDto, nameof(employeeDto.FkDepartment),true,DataSourceUpdateMode.OnPropertyChanged));
}

我编辑或删除员工都没有问题
但是当我添加新员工时出现此错误

Inner Exception 1: SqlException: Cannot insert the value NULL into column 'Name_JobTitle', table 'SIM.dbo.JobTitle'; column does not allow nulls. INSERT fails.

在 JobTitle 表单中,我可以毫无问题地执行 CRUD 操作
这是完整的 StackTrace

Microsoft.EntityFrameworkCore.DbUpdateException
  HResult=0x80131500
  Message=An error occurred while saving the entity changes. See the inner exception for details.
  Source=Microsoft.EntityFrameworkCore.Relational
  StackTrace:
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.<ConsumeAsync>d__2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__103.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__107.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__60.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__60.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Persistence.EFCore.UnitOfWork.<CompleteAsync>d__47.MoveNext() in C:\Users\MBoua\source\repos\SmartWinForm\DataAccess.EFCore\UnitOfWork.cs:line 42
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Application.Service.EmployeeService.<CompleteAsync>d__7.MoveNext() in C:\Users\MBoua\source\repos\SmartWinForm\Application\Service\EmployeeService.cs:line 60
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at SmartWinForm.PL.FrmEmployee.<btnSave_Click>d__29.MoveNext() in C:\Users\MBoua\source\repos\SmartWinForm\SmartWinForm\PL\FrmEmployee.cs:line 290

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
SqlException: Cannot insert the value NULL into column 'Name_JobTitle', table 'SIM.dbo.JobTitle'; column does not allow nulls. INSERT fails.

更新

public partial class JobTitle
{
    public JobTitle()
    {
        Employees = new HashSet<Employee>();
    }

    public int IdJobTitle { get; set; }
    public string NameJobTitle { get; set; }

    public virtual ICollection<Employee> Employees { get; set; }
}
public partial class Employee
{
    public string IdEmployee { get; set; }
    public string FirstNameEmployee { get; set; }
    public string LastNameEmployee { get; set; }
    public int? FkDepartment { get; set; }
    public int? FkJobTitle { get; set; }

    public virtual Department FkDepartmentNavigation { get; set; }
    public virtual JobTitle FkJobTitleNavigation { get; set; }
}

问题是当您将 Dto 映射到 Employee 时,将评估 FkJobTitleNavigation,并且当尝试添加具有 child 的实体(在本例中为 JobTitle)时,EF 尝试添加 child 在插入 parent 之后(parent 是员工)所以你需要解决的问题就是像这样删除 child:

var employee = mapper.Map<Employee>(employeeDto); 
employee.FkJobTitleNavigation =null;  
return await unitOfWork.Employees.AddAsync(employee);