【问题标题】:AspNetCore.Identity UserManager CreateAsync cannot save relationshipsAspNetCore.Identity UserManager CreateAsync 无法保存关系
【发布时间】:2019-02-11 23:10:06
【问题描述】:

我有一个这样的模型:

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 用于我的存储库和服务层,而实体用于在该库中指定可跟踪的实体。

在我的应用层中,我有一个注册用户的服务,我使用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();
    }

代码说明:

GetCountryGetCity 都检查城市和国家是否存在,如果不存在,则创建它们。我在_userService.Insert(newUser) 中插入用户及其与Urf 服务的所有关系,并再次将其保存在单个事务中,Urf 工作单元await _unitOfWork.SaveChangesAsync()

问题:

SaveChangesAsync() 放在_userManager.CreateAsync() 之前,可以毫无问题地创建用户、城市、国家和所有内容。但是,如果我调用 _userManager.CreateAsync(),则 ef 会为国家、城市和用户表中的 id 列抛出异常 'Cannot insert explicit value for identity column...'。

我想在SaveChanges() 的一次调用中保存UserIdentity 和其余关系,但看起来_userManager.CreateAsync() 无法像_unitOfWork.SaveChangesAsync() 那样保存关系。

临时解决方案:

为了暂时通过,我颠倒了UserIdentityUser 中的关系,我首先创建身份,如果成功,我插入其余的:

    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(); 因任何原因失败,则创建身份并且我无法回滚(可能但很脏)

有人知道为什么会出现我解释的问题吗?

【问题讨论】:

    标签: c# asp.net-core entity-framework-core


    【解决方案1】:

    您忽略了发布您的完整控制器,特别是正在注入的服务,但根据您的问题,我猜您正在注入 UserManager<IdentityUser>

    这里的类型参数是实际要检索、持久化等的内容。因此,如果您尝试保存 UserIdentity 实例,它将被向上转换为 IdentityUser(没有您的 @987654324 @property),而 that 就是将要创建的内容。如果你需要使用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&lt;User&gt; 并直接使用UserUserIdentity 进入垃圾箱。

    【讨论】:

    • 好吧,我已经注入了UserManager&lt;UserIdentity&gt;,所以情况并非如此。关于丢弃 UserIdentity,我真的不喜欢 User 对象被身份问题搞砸,尤其是在消费者不需要知道任何关于用户身份的情况下,反之亦然。也许我的命名是错误的选择用户作为它的名字。但是谢谢你的回答。我会更新我的问题以获取更多详细信息。
    猜你喜欢
    • 1970-01-01
    • 2020-08-13
    • 2017-09-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 2021-11-13
    • 1970-01-01
    相关资源
    最近更新 更多