c# - AspNetCore.Identity UserManager CreateAsync 无法保存关系
问题描述
我有一个这样的模型:
public class UserIdentity : IdentityUser
{
public User User { get; set; }
}
public class User : Entity
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime DateOfBirth { get; set; }
public Occupation Occupation { get; set; }
public Country Country { get; set; }
public City City { get; set; }
public Ethnicity Ethnicity { get; set; }
public GenderEnum Gender { get; set; }
}
IdentityUser 在AspNetCore.Identity
命名空间中。此外,我将Urf.Core用于我的存储库和服务层,而 Entity 用于在该库中指定可跟踪的实体。
在我的应用程序层中,我有一个用于注册用户的服务,我用它UserManager<UserIdentity>
来保存用户。
public async Task Register(UserRegistrationDto dto)
{
var newUser = new User();
var country = GetCountry(dto.CountryName);
var city = GetCity(country, dto.CityName, dto.CityId.Value);
var ethnicity = GetEthnicity(dto.EthnicityId.Value);
var occupation = GetOccupation(dto.OccupationId.Value);
newUser.Country = country;
newUser.City = city;
newUser.Occupation = occupation;
newUser.Ethnicity = ethnicity;
newUser.DateOfBirth = dto.DateOfBirth;
newUser.Name = dto.Name;
newUser.Surname = dto.Surname;
newUser.Gender = (GenderEnum)dto.Gender.Value;
_userService.Insert(newUser);
var newIdentity = new UserIdentity {UserName = dto.Email, Email = dto.Email, User = newUser};
var result = await _userManager.CreateAsync(newIdentity, dto.Password);
//await _unitOfWork.SaveChangesAsync();
}
代码说明:
GetCountry
and ,GetCity
两者都检查城市和国家是否存在,如果不存在,则创建它们。我将用户及其与 Urf 服务的所有关系插入其中_userService.Insert(newUser)
,并将其全部保存在单个事务中,再次使用 Urf 工作单元,await _unitOfWork.SaveChangesAsync()
问题:
放置SaveChangesAsync()
在之前_userManager.CreateAsync()
,创建用户,城市,国家和所有没有任何问题。但是,如果我调用_userManager.CreateAsync()
, ef 会为国家、城市和用户表中的 id 列抛出异常“无法为标识列插入显式值...”。
我想UserIdentity
在一次调用中保存和其余的关系SaveChanges()
,但看起来_userManager.CreateAsync()
不能像这样保存关系_unitOfWork.SaveChangesAsync()
。
临时解决方案:
为了暂时通过,我颠倒了 and 中的关系UserIdentity
,User
我首先创建身份,如果成功,我插入其余的:
public async Task Register(UserRegistrationDto dto)
{
var newIdentity = UserIdentity.CreateIdentity(dto.Email, dto.Email, dto.Phone);
var result = await _userManager.CreateAsync(newIdentity, dto.Password);
if (result.Succeeded)
{
var newUser = new User();
var country = GetCountry(dto.CountryName);
var city = GetCity(country, dto.CityName, dto.CityId.Value);
var ethnicity = GetEthnicity(dto.EthnicityId.Value);
var occupation = GetOccupation(dto.OccupationId.Value);
newUser.Identity = newIdentity;
newUser.Country = country;
newUser.City = city;
newUser.Occupation = occupation;
newUser.Ethnicity = ethnicity;
newUser.DateOfBirth = dto.DateOfBirth;
newUser.Name = dto.Name;
newUser.Surname = dto.Surname;
newUser.Gender = (GenderEnum)dto.Gender.Value;
_userService.Insert(newUser);
await _unitOfWork.SaveChangesAsync();
}
}
但如您所见,它将它们保存在两个单独的事务中,如果_unitOfWork.SaveChangesAsync();
由于任何原因失败,则创建身份并且我无法回滚(可能但很脏)
有谁知道为什么我解释的问题会发生?
解决方案
您忽略了发布您的完整控制器,特别是正在注入的服务,但根据您的问题,我猜您正在注入UserManager<IdentityUser>
.
这里的类型参数是实际将要检索、持久化等的内容。因此,如果您尝试保存UserIdentity
实例,它将被向上转换为IdentityUser
(没有您的User
属性),这就是将要创建的内容. 如果你需要使用UserIdentity
,那么你需要注入UserManager<UserIdentity>
。
但是,您在这里的设计是完全错误的。通用用户类型的全部意义在于允许可扩展性。您应该创建一个类,该类直接从那里继承IdentityUser
并为您的用户指定任何其他属性。您不需要也不应该通过组合添加单独的配置文件样式类。换句话说:
public class User : IdentityUser
{
public string Name { get; set; }
public string Surname { get; set; }
public DateTime DateOfBirth { get; set; }
public Occupation Occupation { get; set; }
public Country Country { get; set; }
public City City { get; set; }
public Ethnicity Ethnicity { get; set; }
public GenderEnum Gender { get; set; }
}
然后,在 Startup.cs 中:
services.AddDefaultIdentity<User>();
在您的控制器中,直接注入UserManager<User>
和使用User
。UserIdentity
进入垃圾箱。
推荐阅读
- autodesk-forge - 无法接收 Forge webhook,或无法触发它们
- c# - 如何仅终止本地计算机的远程桌面会话
- amazon-web-services - amazon dynamodb 中的分区键和排序键有什么区别?
- .net-core - Azure Pipeline 中 .NetCore、VisualStudio 构建和 MSBuild 任务之间的区别?
- ruby-on-rails - 显示具有特定类别的所有广告,不返回任何内容 - Rails 5
- code-coverage - Gitlab管道-当Jacoco报告覆盖率低于主分支中的最后一次提交时如何使管道失败?
- linux - 尝试在 python 脚本中通过 ssh 访问其他系统的相机时出错
- reactjs - 使用 nwb 发布现有的 create-react-app
- c# - 动画状态..因为找不到而无法播放?
- google-cloud-platform - 将 dataproc 集群连接到 Cloud SQL 实例时,没有要代理的 Cloud SQL 实例