我有一个这样的模型:
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
和GetCity
都检查城市和国家/地区是否存在,如果不存在,则会创建城市和国家/地区。我在_userService.Insert(newUser)
中插入用户及其与Urf服务的所有关系,并将其与Urf工作单元await _unitOfWork.SaveChangesAsync()
问题:
将SaveChangesAsync()
放在_userManager.CreateAsync()
之前,可以毫无问题地创建用户,城市,国家和地区。但是,如果我调用_userManager.CreateAsync()
,则ef会为国家,城市和用户表中的id列引发异常“无法为标识列插入显式值...”。
我想在一次UserIdentity
调用中保存SaveChanges()
和其余关系,但是看起来_userManager.CreateAsync()
无法像_unitOfWork.SaveChangesAsync()
那样保存关系。 / p>
临时解决方案:
现在要获得通行证,我颠倒了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();
由于任何原因失败,则将创建身份并且我无法回滚(可能但很脏)
有人知道我解释的问题为什么会发生吗?
答案 0 :(得分:0)
您忽略发布完整的控制器,特别是要注入的服务,但是基于您的问题,我猜您是在注入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
丢进了垃圾桶。