我选择在基础设施层定义这样的 ApplicationUser 类:
namespace MySolution.Infrastructure.Context
{
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
public EmployeeId EmployeeId { get; set; }
public Employee Employee { get; set; }
}
}
我还创建了一个用于将用户连接到员工的表
namespace MySolution.Infrastructure.Context
{
public class EmployeeUserMap
{
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public EmployeeId EmployeeId { get; set; }
public Employee Employee { get; set; }
}
}
这是我的域层中的实体:
namespace MySolution.Domain.Entities
{
public class Employee
{
//empty constructor
private Employee() { } // Required by EF core
//properties
public EmployeeId Id { get; init; }
public required VatNumber WorkplaceVAT { get; init; }
public required string EmployeeName { get; set; }
public required Address Address { get; set; }
public required ContactInfo ContactInfo { get; set; }
public required UserRole Role { get; set; }
public string? ApplicationUserId { get; set; }
public CompanyId CompanyId { get; init; }
//Navigational properties
public Company Company { get; set; }
[SetsRequiredMembers]
public Employee(string name, ContactInfo contactInfo, Address address, VatNumber workplaceVAT, UserRole role, CompanyId companyId, string applicationUserId)
{
Id = EmployeeId.Create();
EmployeeName = name ?? throw new ArgumentNullException(nameof(name));
ContactInfo = contactInfo ?? throw new ArgumentNullException(nameof(contactInfo));
Address = address ?? throw new ArgumentNullException(nameof(address));
WorkplaceVAT = workplaceVAT ?? throw new ArgumentNullException(nameof(workplaceVAT));
Role = role;
CompanyId = companyId;
ApplicationUserId = applicationUserId;
Validate(this);
}
private static void Validate(Employee employee)
{
var context = new ValidationContext(employee);
Validator.ValidateObject(employee, context, validateAllProperties : true);
}
public void ChangeContactDetails(ContactInfo newContactDetails)
{
ContactInfo = newContactDetails ?? throw new ArgumentNullException(nameof(newContactDetails));
}
public void ChangeAddress(Address newAddress)
{
Address = newAddress ?? throw new ArgumentNullException(nameof(newAddress));
}
}
}
我不知道如何保持域层独立,而是将 ApplicationUserId 传递给实体。我希望 Employee-ApplicationUser 之间存在一对一的关系,并且我希望能够首先创建一个 Employee 并使 applicationId 可为空,接下来我希望仅当具有相同邮件的员工存在时才能注册用户.
public async Task RegisterUser(EditContext editContext)
{
var employee = await _mediator.Send(new GetEmployeeByEmailQuery(Input.Email), default);
if (employee != null)
{
var user = CreateUser();
await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
var emailStore = GetEmailStore();
await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
user.EmployeeId = employee.Id;
var result = await UserManager.CreateAsync(user, Input.Password);
if (!result.Succeeded)
{
identityErrors = result.Errors;
return;
}
await UserManager.UpdateAsync(user);
employee.ApplicationUserId = user.Id;
await _mediator.Send(new UpdateEmployeeCommand(new VatNumber(employee.WorkplaceVat), employee.Name, AddressMapper.ToValueObject(employee.Address), ContactInfoMapper.ToValueObject(employee.ContactInfo), employee.ApplicationUserId!, employee.Role, employee.CompanyId), default);
Logger.LogInformation("User created a new account with password.");
var userId = await UserManager.GetUserIdAsync(user);
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri,
new Dictionary<string, object?> { ["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl });
await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl));
if (UserManager.Options.SignIn.RequireConfirmedAccount)
{
RedirectManager.RedirectTo(
"Account/RegisterConfirmation",
new() { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl });
}
await SignInManager.SignInAsync(user, isPersistent: false);
RedirectManager.RedirectTo(ReturnUrl);
}
else
{
identityErrors = new List<IdentityError> { new IdentityError { Description = "Employee not found for the provided email." } };
}
}
要在链接 Employee 和 ApplicationUser 时保持域独立性,您可以尝试以下方法:
1.在领域层让员工远离基础设施依赖。包含一个可为空的 ApplicationUserId 并添加一个方法来链接它。
2.在基础设施层中,在 DbContext 中配置 EF Core 以实现一对一关系。
3.在Service层处理注册逻辑。首先,创建 Employee,然后注册 ApplicationUser,将 ApplicationUserId 链接到 Employee,并更新这两个实体。这确保了服务层中的域完整性和正确链接