I am implementing Entity Framework in ASP.NET Core-6 Web API and MSSQL DB. I have this code:
Models:
public class BankUser
{
public Guid { get; set; }
[ForeignKey("UserId")]
public string UserId { get; set; }
public string Description { get; set; }
[ForeignKey("BankBranchId")]
public Guid BankBranchId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual BankBranch BankBranch { get; set; }
}
public class BankBranch
{
public Guid { get; set; }
public string BranchName { get; set; }
public virtual BankUser BankUser { get; set; }
}
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual BankUser BankUser { get; set; }
}
BankBranch has many BankUser, while BankUser and Application User is one-to-one.
Configuration:
public class ApplicationUserConfigurations : IEntityTypeConfiguration<ApplicationUser>
{
public void Configure(EntityTypeBuilder<ApplicationUser> builder)
{
builder.Property(u => u.IsDeleted).HasDefaultValue(false);
}
}
public void Configure(EntityTypeBuilder<BankBranch> builder)
{
builder.ToTable(name: "bank_branches");
builder.HasKey(b => b.Id);
builder.Property(b => b.Id).HasDefaultValueSql("NEWID()");
builder.HasIndex(b => b.BranchName).IsUnique();
builder.HasIndex(b => b.BranchNumber).IsUnique();
}
}
public class BankUserConfigurations : IEntityTypeConfiguration<BankUser>
{
public void Configure(EntityTypeBuilder<BankUser> builder)
{
builder.ToTable(name: "bank_users");
builder.HasKey(b => b.Id);
builder.Property(b => b.Id).HasDefaultValueSql("NEWID()");
}
}
Then this is the Dto:
public class BankUserCreateDto
{
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Role { get; set; }
public string MobileNumber { get; set; }
public Guid BankBranchId { get; set; }
}
Finally the implementation:
public async Task<Response<string>> CreateBankUserAsync(BankUserCreateDto model)
{
var response = new Response<string>();
using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var bankUser = _mapper.Map<ApplicationUser>(model);
var bankPassword = "@Password*123";
var result = await _userManager.CreateAsync(bankUser, bankPassword);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(bankUser, model.Role);
var user = new BankUser()
{
UserId = bankUser.Id,
BankBranchId = model.BankBranchId,
Description = model.Description,
CreatedBy = _currentUserService.UserName
};
await _unitOfWork.AdminUsers.InsertAsync(user);
await _unitOfWork.Save();
_logger.Information("Bank User created successfully");
response.StatusCode = (int)HttpStatusCode.Created;
response.Successful = true;
response.Data = _mapper.Map<BankUserDto>(bankUser);
response.Message = "Bank User created successfully!";
transaction.Complete();
return response;
}
return response;
};
}
When I submitted, I got this error:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details. ---> Microsoft.Data.SqlClient.SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_bank_users_bank_branches_BankBranchId". The conflict occurred in database "ERPs", table "dbo.bank_branches", column 'Id'. The statement has been terminated.
How do I get this sorted out?
Thanks
CodePudding user response:
I think you're having an issue with BankBranch
not being populated. If that entity set (table) is empty, then when you're trying to add a BankUser
there is no branch to map them to.
Also, you mentioned that BankBranches
have many BankUsers
. Your code explicitly says in BankBranch
:
public virtual BankUser BankUser { get; set; }
This communicates that there is 1 BankUser
to the BankBranch
. I think you'd rather want:
public virtual IColelction<BankUser> BankUsers { get; set; }
And it seems you're mixing Attributes with FluentAPI. While this can be done, I would suggest trying to stick to one way or the other unless there's a reason not to. Even MS-EF says that attributes can do much of hard work, but FluentAPI is better for your edge cases.