urfnet / URF.Core

Unit of Work & Repositories Framework - .NET Core, NET Standard, Entity Framework Core. 100% extensible & lightweight.
https://github.com/urfnet
MIT License
309 stars 62 forks source link

issue with using AspNetCore.Identity UserManager<IdentityUser> CreateAsync() #53

Closed aliBordbar1992 closed 5 years ago

aliBordbar1992 commented 5 years ago

having a model like this

public class UserIdentity : IdentityUser
    {
        public virtual TestEntity test { get; private set; }
    }

public class TestEntity : Entity
    {
        public int Id { get; set; }
        public string name { get; set; }
    }

and a service like this

public class UserRegistrationService : IUserRegistrationService
    {
        private readonly UserManager<UserIdentity> _userManager;
        private readonly ITestEntityService _t;

        public UserRegistrationService(IServiceProvider serviceProvider, UserManager<UserIdentity> userManager)
        {
            _userManager = userManager;
            _t = serviceProvider.GetRequiredService<ITestEntityService>();
        }

        public async Task Register(UserRegistrationDto userRegistrationDto)
        {
            var t = new TestEntity{name = "test"};
            _t.Insert(t);
            var newIdentity = new UserIdentity { test = t };
            var result = await _userManager.CreateAsync(newIdentity, userRegistrationDto.Password);
        }
    }

the following exception is thrown calling _userManager.CreateAsync(): SqlException: Cannot insert explicit value for identity column in table 'TestEntities' when IDENTITY_INSERT is set to OFF.

the same happens with a scenario like this:

public class UserIdentity : IdentityUser
    {
        public virtual User User { get; private set; }
        public static UserIdentity CreateIdentity(string username, string email, User newUser, string phoneNumber = "")
        {
            var newUserIdentity = new UserIdentity
            {
                UserName = username,
                Email = email,
                EmailConfirmed = false,
                PhoneNumber = phoneNumber,
                PhoneNumberConfirmed = false,
                User = newUser
            };

            return newUserIdentity;
        }
    }

public class User : Entity
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public DateTime DateOfBirth { get; set; }
        public virtual Occupation Occupation { get; set; }
        public virtual Country Country { get; set; }
        public virtual City City { get; set; }
        public virtual Ethnicity Ethnicity { get; set; }
        public GenderEnum Gender { get; set; }
    }

and the service that actually I have is:

public UserRegistrationService(IServiceProvider serviceProvider, UserManager<UserIdentity> userManager)
        {
            _userManager = userManager;
            _countryService = serviceProvider.GetRequiredService<ICountryService>();
            _cityService = serviceProvider.GetRequiredService<ICityService>();
            _ethnicityService = serviceProvider.GetRequiredService<IEthnicityService>();
            _occupationService = serviceProvider.GetRequiredService<IOccupationService>();
            _userService = serviceProvider.GetRequiredService<IUserService>();

            _unitOfWork = serviceProvider.GetRequiredService<IUnitOfWork>();
        }

        public async Task Register(UserRegistrationDto userRegistrationDto)
        {
            var newUser = new User();

            var country = GetCountry(userRegistrationDto.CountryName);
            var city = GetCity(country, userRegistrationDto.CityName, userRegistrationDto.CityId.Value);

            var ethnicity = GetEthnicity(userRegistrationDto.EthnicityId.Value);
            var occupation = GetOccupation(userRegistrationDto.OccupationId.Value);

            newUser.Country = country;
            newUser.City = city;
            newUser.Occupation = occupation;
            newUser.Ethnicity = ethnicity;

            newUser.DateOfBirth = userRegistrationDto.DateOfBirth;

            newUser.Name = userRegistrationDto.Name;
            newUser.Surname = userRegistrationDto.Surname;
            newUser.Gender = (GenderEnum)userRegistrationDto.Gender.Value;

            var newIdentity = UserIdentity.CreateIdentity(userRegistrationDto.Email, userRegistrationDto.Email, newUser, userRegistrationDto.Phone);
            var result = await _userManager.CreateAsync(newIdentity, userRegistrationDto.Password);
        }

private Country GetCountry(string countryName)
        {
            if (CountryExistsInDb(countryName))
                return _countryService.Queryable().First(x => x.Name.Equals(countryName));

            var newCountry = new Country { Name = countryName };

            return newCountry;
        }
        private bool CountryExistsInDb(string countryName)
        {
            return _countryService.Queryable().Any(x => x.Name.Equals(countryName));
        }

        private City GetCity(Country country, string cityName, int cityId)
        {
            if (CityExistsInDb(cityId))
                return _cityService.Queryable().First(x => x.CustomCityId == cityId);

            var newCity = new City { CustomCityId = cityId, Country = country, Name = cityName };

            return newCity;
        }
        private bool CityExistsInDb(int cityId)
        {
            return _cityService.Queryable().Any(x => x.CustomCityId == cityId);
        }

        private Ethnicity GetEthnicity(int ethnicityId)
        {
            return _ethnicityService.FindAsync(ethnicityId).Result;
        }

        private Occupation GetOccupation(int occupationId)
        {
            return _occupationService.FindAsync(occupationId).Result;
        }

but this time it tries to insert the Ethnicity, or Occupation, even though they are not new entities. the exception is:

SqlException: Cannot insert explicit value for identity column in table 'Ethnicities' when IDENTITY_INSERT is set to OFF.
System.Data.SqlClient.SqlCommand+<>c.<ExecuteDbDataReaderAsync>b__122_0(Task<SqlDataReader> result)
System.Threading.Tasks.ContinuationResultTaskFromResultTask<TAntecedentResult, TResult>.InnerInvoke()
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, object state)
System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref Task currentTaskSlot)
Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteAsync(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary<string, object> parameterValues, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
aliBordbar1992 commented 5 years ago

here is my following SO question AspNetCore.Identity UserManager CreateAsync cannot save relationships

lelong37 commented 5 years ago

Please turn on enable IdentityInsert on columns on your tables that are PrimaryKeys, this is a SQL and EF question, unrelated to Urf.Core, closing this issue.