简体   繁体   English

AspNetCore.Identity UserManager CreateAsync无法保存关系

[英]AspNetCore.Identity UserManager CreateAsync cannot save relationships

I have a model like this: 我有一个这样的模型:

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; }
}

the IdentityUser is in AspNetCore.Identity namespace. IdentityUser位于AspNetCore.Identity命名空间中。 Also, I'm using Urf.Core for my repository and service layer, and the Entity is for specifying trackable entities in that library. 另外,我将Urf.Core用于我的存储库和服务层,并且Entity用于在该库中指定可跟踪的实体。

in my Application layer I have a service for registering users and I use UserManager<UserIdentity> to save users. 在我的应用程序层中,我有一个用于注册用户的服务,并且我使用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();
    }

Code explanation: 代码说明:

the GetCountry and GetCity , both check if the city and country exists or not, and if not it creates them. GetCountryGetCity ,都检查城市和国家/地区是否存在,如果不存在,则创建城市和国家/地区。 I insert the user and all its relations with Urf service in _userService.Insert(newUser) and save it all together in single transaction with again, Urf unit of work, await _unitOfWork.SaveChangesAsync() 我将用户及其与_userService.Insert(newUser)服务的所有关系插入_userService.Insert(newUser) ,并将其全部与单个await _unitOfWork.SaveChangesAsync()工作单元一起保存在单个事务中, await _unitOfWork.SaveChangesAsync()

The problem: 问题:

placing SaveChangesAsync() before _userManager.CreateAsync() , creates the user, city, country and all without any problem. SaveChangesAsync()放在_userManager.CreateAsync() SaveChangesAsync()之前,可以_userManager.CreateAsync()创建用户,城市,国家和所有地区。 But if I call _userManager.CreateAsync() , ef throws exception 'Cannot insert explicit value for identity column...' for id column in country, city, and user tables. 但是,如果我调用_userManager.CreateAsync() ,则ef会为国家,城市和用户表中的id列引发异常“无法为标识列插入显式值...”。

I want to save the UserIdentity and rest of the relationships in one call of SaveChanges() , but looks like _userManager.CreateAsync() cannot save relations like the way _unitOfWork.SaveChangesAsync() can. 我想保存UserIdentity的关系和休息的一个调用SaveChanges()但看起来像_userManager.CreateAsync()不能保存喜欢的方式关系_unitOfWork.SaveChangesAsync()即可。

Temoporary solution: 临时解决方案:

to get pass for now, I reversed the relations in UserIdentity and User , I create the identity first and if that succeeds I insert rest of them: 为了UserIdentity获得通过,我反转了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();
        }
    }

but as you can see, it saves them in two seperate transactions, if _unitOfWork.SaveChangesAsync(); 但如您所见,如果_unitOfWork.SaveChangesAsync();它将保存在两个单独的事务中_unitOfWork.SaveChangesAsync(); fails for any reason, the identity is created and I can't rollback (it is possible but dirty) 由于任何原因而失败,创建了身份,并且我无法回滚(可能但很脏)

does anyone know why the problem I explained, happens? 有谁知道为什么我解释的问题会发生?

You neglected to post your full controller, particularly the services that are being injected, but based on your issue, I'm guessing you're injecting UserManager<IdentityUser> . 您忽略了发布完整的控制器,特别是要注入的服务,但是基于您的问题,我猜测您正在注入UserManager<IdentityUser>

The type param here is what is actually going to be retrieved, persisted, etc. So, if you attempt to save a UserIdentity instance, it will be upcast to IdentityUser (which doesn't have your User property), and that is what's going to be created. 这里的类型参数实际上是将要检索,保留等的内容。因此,如果您尝试保存UserIdentity实例,它将被转换为IdentityUser (不具有User属性), 就是事实被创建。 If you need to work with UserIdentity , then you need to inject UserManager<UserIdentity> . 如果需要使用UserIdentity ,则需要注入UserManager<UserIdentity>

However, your design here is completely wrong. 但是,这里的设计是完全错误的。 The whole point of the user type being generic is to allow extensibility. 用户类型的整体要点是允许扩展。 You should create a class that inherits from IdentityUser and specify any additional properties for your user directly there. 您应该创建一个从IdentityUser继承的类,并直接在此处为用户指定任何其他属性。 You do not need and should not have a separate profile-style class added in via composition. 您不需要也不需要通过组合添加单独的配置文件样式类。 In other words: 换一种说法:

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; }
}

Then, in Startup.cs: 然后,在Startup.cs中:

services.AddDefaultIdentity<User>();

And in your controller, inject UserManager<User> and work with User directly. 在您的控制器中,注入UserManager<User>并直接与User一起User UserIdentity goes in the trash. UserIdentityUserIdentity

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在界面中使用 AspNetCore.Identity RoleManager 和 UserManager - Use AspNetCore.Identity RoleManager and UserManager in an Interface AspNetCore.Identity中的Google身份验证 - Google authentication in AspNetCore.Identity AspNetCore.Identity重置密码-无法跟踪“ X”的实例 - AspNetCore.Identity Reset Password - Instance of 'X' cannot be tracked AspNetCore.Identity userManager.FindByNameAsync 在找到所述用户时抛出访问冲突异常 - AspNetCore.Identity userManager.FindByNameAsync throws Access Violation Exception upon finding said user 将 AddPooledDbContextFactory 与 AspNetCore.Identity 一起使用 - Using AddPooledDbContextFactory with AspNetCore.Identity 覆盖AspNetCore.Identity表中的默认索引 - Override default indexes in AspNetCore.Identity tables AspNetCore.Identity LockoutOptions.AllowedForNewUsers属性 - AspNetCore.Identity LockoutOptions.AllowedForNewUsers Property ViewComponent 无法识别 AspNetCore.Identity“用户” - ViewComponent does not recognize AspNetCore.Identity "User" Identity UserManager CreateAsync 不写入数据库 - Identity UserManager CreateAsync does not write to database 名称不能为null或为空:_userManager.CreateAsync - Name cannot be null or empty: _userManager.CreateAsync
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM