In my application I am using unit of work and repository pattern and auto mapper
This is the 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; }
}
And this 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; }
}
this is the code generated by 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);
}
in JobTitleService I get all JobTitle like this
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);
}
}
And this is how I get and added employees
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);
}
and this is the code behind the employee form
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));
}
There is no problem when I edited or deleted employees
but when I add new employee I get this error
Inner Exception 1: SqlException: Cannot insert the value NULL into column 'Name_JobTitle', table 'SIM.dbo.JobTitle'; column does not allow nulls. INSERT fails.
In JobTitle form I can perform CRUD operations without any problems
this is the full 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.
Update
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; }
}
CodePudding user response:
The problem is when you map the Dto to Employee the FkJobTitleNavigation
will be evaluated, and when try to adding an entity with child (in this case is JobTitle) EF try to add child after parent inserted (parent is employee) so all you need to solve your problem is remove the child like this:
var employee = mapper.Map<Employee>(employeeDto);
employee.FkJobTitleNavigation =null;
return await unitOfWork.Employees.AddAsync(employee);