Я обновляю. NET Core Web API с 2.2 до 3.1. При тестировании функции ChangePasswordAsync
я получаю следующее сообщение об ошибке:
Невозможно обновить столбец идентификатора 'UserId'.
Я запустил профиль SQL и я Можно видеть, что столбец Identity не включен в оператор 2.2 UPDATE, но находится в 3.1.
Соответствующая строка кода возвращает NULL, в отличие от успеха или ошибок, и выглядит следующим образом:
objResult = await this.UserManager.ChangePasswordAsync(objUser, objChangePassword.OldPassword, objChangePassword.NewPassword);
Реализация ChangePasswordAsnyc
выглядит следующим образом (код, усеченный для краткость).
Примечание: AspNetUsers расширяет IdentityUser.
[HttpPost("/[controller]/change-password")]
public async Task<IActionResult> ChangePasswordAsync([FromBody] ChangePassword objChangePassword)
{
AspNetUsers objUser = null;
IdentityResult objResult = null;
// retrieve strUserId from the token.
objUser = await this.UserManager.FindByIdAsync(strUserId);
objResult = await this.UserManager.ChangePasswordAsync(objUser, objChangePassword.OldPassword, objChangePassword.NewPassword);
if (!objResult.Succeeded)
{
// Handle error.
}
return this.Ok(new User(objUser));
}
UserId
включается в objResult вместе со многими другими полями, которые затем возвращаются в конце метода. Из того, что я могу сказать, не имея возможности пошагово выполнять метод ChangePasswordAsync
, функция обновляет все поля, содержащиеся в objUser
.
Вопрос:
Как запретить заполнение столбца идентификации в инструкции UPDATE, которую генерирует ChangePasswordAsnyc
? Нужно ли добавить атрибут в модель? Нужно ли удалять UserId
из objUser
перед тем, как передать его в ChangePasswordAsync
? Или что-то еще?
Вопрос о награде Я создал пользовательский класс пользователя, который расширяет класс IdentityUser
. В этом пользовательском классе есть дополнительный столбец IDENTITY. При обновлении. NET Core 2.2 до 3.1 функция ChangePasswordAsync
больше не работает, поскольку метод 3.1 пытается обновить этот столбец IDENTITY, тогда как в 2.1 это не происходит.
Не было никакого изменения кода кроме обновления установки соответствующих пакетов. Принятый ответ должен устранить проблему.
ОБНОВЛЕНИЕ
Миграции не используются, поскольку это приводит к принудительному браку между базой данных и веб-API с соответствующими моделями. , На мой взгляд, это нарушило разделение обязанностей между базой данных, API и пользовательским интерфейсом. Но это опять Microsoft по-старому.
У меня есть свои собственные определенные методы ADD, UPDATE и DELETE, которые используют EF и устанавливают EntityState. Но при пошаговом выполнении кода для ChangePasswordAsync
я не вижу ни одной из этих вызванных функций. Это как если бы ChangePasswordAsync
использовал базовые методы в EF. Итак, я не знаю, как изменить это поведение. из ответа Ивана.
Примечание: я опубликовал вопрос, чтобы попытаться понять, как метод ChangePasswordAsync
вызывает EF здесь [Может кто-нибудь объяснить, как работает метод ChangePasswordAsny c?] [1].
пространство имен AB C .Model.AspNetCore
using ABC.Common.Interfaces;
using ABC.Model.Clients;
using Microsoft.AspNetCore.Identity;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ABC.Model.AspNetCore
{
// Class for AspNetUsers model
public class AspNetUsers : IdentityUser
{
public AspNetUsers()
{
// Construct the AspNetUsers object to have some default values here.
}
public AspNetUsers(User objUser) : this()
{
// Populate the values of the AspNetUsers object with the values found in the objUser passed if it is not null.
if (objUser != null)
{
this.UserId = objUser.UserId; // This is the problem field.
this.Email = objUser.Email;
this.Id = objUser.AspNetUsersId;
// Other fields.
}
}
// All of the properties added to the IdentityUser base class that are extra fields in the AspNetUsers table.
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int UserId { get; set; }
// Other fields.
}
}
пространство имен AB C .Model.Clients
using ABC.Model.AspNetCore;
using JsonApiDotNetCore.Models;
using System;
using System.ComponentModel.DataAnnotations;
namespace ABC.Model.Clients
{
public class User : Identifiable
{
public User()
{
// Construct the User object to have some default values show when creating a new object.
}
public User(AspNetUsers objUser) : this()
{
// Populate the values of the User object with the values found in the objUser passed if it is not null.
if (objUser != null)
{
this.AspNetUsersId = objUser.Id;
this.Id = objUser.UserId; // Since the Identifiable is of type Identifiable<int> we use the UserIdas the Id value.
this.Email = objUser.Email;
// Other fields.
}
}
// Properties
[Attr("asp-net-users-id")]
public string AspNetUsersId { get; set; }
[Attr("user-id")]
public int UserId { get; set; }
[Attr("email")]
public string Email { get; set; }
[Attr("user-name")]
public string UserName { get; set; }
// Other fields.
}
}
EntitiesRepo
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace ABC.Data.Infrastructure
{
public abstract class EntitiesRepositoryBase<T> where T : class
{
#region Member Variables
protected Entities m_DbContext = null;
protected DbSet<T> m_DbSet = null;
#endregion
public virtual void Update(T objEntity)
{
this.m_DbSet.Attach(objEntity);
this.DbContext.Entry(objEntity).State = EntityState.Modified;
}
}
}