Обновление пользовательской записи Identity создает новую запись для элемента навигации - PullRequest
0 голосов
/ 20 мая 2019

У меня есть «довольно стандартная» Entity Framework с настройкой Identity, в которой я добавил свойство навигации по внешнему ключу для адреса пользователя. Когда я прихожу обновить запись, элемент адреса снова добавляется в базу данных с новым автоматически увеличенным идентификатором.

Я видел в другом месте этого прославленного форума, что это может быть вызвано наличием двух контекстов БД, но я не думаю, что у меня есть эта проблема (но, возможно, не могу ее обнаружить?), И попробовал исправление, предложенное там: UserManager обновляет запись пользователя, но также создает новую запись . Здесь есть некоторая история, которая начиналась как два контекста БД, но я (думаю, я) свел их в один, так как два не были нужны. Вот основная функция обновления: (Примечание: я закомментировал исправление, которое я пробовал из другого вопроса SO).

    // POST api/Account/UpdateUserDetail
    [Route("UpdateUserDetail")]
    public async Task<IHttpActionResult> UpdateUserDetail(SGGUserDTO usertoupdate)
    {
        //using (SGGContext ctx = new SGGContext())
        //{
        //    ApplicationUserManager UserManager = new ApplicationUserManager(new UserStore<SGGUser>(ctx));
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            string userid = User.Identity.GetUserId(); //Check user is valid
            if (usertoupdate.Id != userid)
            {
                return NotFound();
            }
            SGGUser user = await UserManager.FindByIdAsync(userid);
            if (user == null)
            {
                return NotFound();
            }
            Mapper.Map(usertoupdate, user);
            var result = await UserManager.UpdateAsync(user);
            if (result.Succeeded)
            {
                return Ok();
            }
            else
            {
                return GetErrorResult(result);
            }
        //}

    }

Метод обновления в контроллере API и его инициализация выглядит следующим образом:

    public class AccountController : ApiController
{
    private const string LocalLoginProvider = "Local";
    private SGGContext db = new SGGContext();
    private ApplicationUserManager _userManager;
    public AccountController()
    {
    }

    public AccountController(ApplicationUserManager userManager,
        ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
    {
        UserManager = userManager;
        AccessTokenFormat = accessTokenFormat;
    }

    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

Моя модель идентичности выглядит так:

    public class SGGUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<SGGUser> manager, string authenticationType = DefaultAuthenticationTypes.ApplicationCookie)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
        // Add custom user claims here
        return userIdentity;
    }

    [Display(Name = "Date of Birth")]
    [DataType(DataType.DateTime)]
    [DisplayFormat(DataFormatString = "{0:d}",
        NullDisplayText = "Please Enter Your Date of Birth",
        ApplyFormatInEditMode = true)]

    public DateTime? DateOfBirth { get; set; }
    public string Title { get; set; }
    public string FirstName { get; set; }

    .... bunch of stuff

    public Address Address { get; set; }
    public virtual BusinessUser BusinessUser { get; set; }
    public virtual BusinessCustomer BusinessCustomer { get; set; }

    .... bunch more stuff
}

ApplicationUserManager это:

    public class ApplicationUserManager : UserManager<SGGUser>
{
    public ApplicationUserManager(IUserStore<SGGUser> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var  db = new SGGContext();
        var manager = new ApplicationUserManager(new UserStore<SGGUser>(context.Get<SGGContext>()));

        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<SGGUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {

  .... Bunch more stuff
            return manager;
    }

... и контекст базы данных (SGGContext) выглядит следующим образом:

    public class SGGContext : IdentityDbContext<SGGUser>
{
    public SGGContext()
        : base("SGGContext", throwIfV1Schema: false)
    {
    }

    static SGGContext()
    {
        Database.SetInitializer(new sggDbInitializer_on_change());
    }

    public static SGGContext Create()
    {
        return new SGGContext();
    }

    public DbSet<Address> Addresses { get; set; }

    public DbSet<Business> Businesses { get; set; }

    .... bunch more things

}

Если честно, я подумал, что все это довольно странно.

Но когда я обновляю запись с помощью адреса, пользователь обновляется очень хорошо, но к объекту адреса добавляется новая запись. Я также нашел другой пост по SO здесь: Обновление записи EF создает новую запись для связанного объекта и я попытался использовать .Attach, но я боюсь, что я не мог заставить это работать, поскольку это выдало ошибку.

Может кто-нибудь определить, где у меня случайно есть два контекста, или определить проблему? Большое спасибо.

...