Я использую встроенную систему идентификации для управления пользователями и хотел бы добавить несколько настроек в таблицу AspNetUsers. До сих пор решение каждой проблемы, с которой я столкнулся, вызывает еще одну проблему.
Если я вношу изменения в модель пользователя (например, добавив свойство zip-кода и соответствующее поле в таблице AspNetUsers), затем вызовите UserManager.UpdateAsync(пользователь), он будет успешным, но не обновит поле почтового индекса в базы данных.
Как минимум еще один вопрос SO попытался справиться с этим. Но предлагаемые исправления там нарушают другие вещи:
1) Создание другого экземпляра UserDbContext и попытка присоединения объекта пользователя заставляет сущность-структуру жаловаться на то, что "объект-объект не может ссылаться на несколько экземпляров IEntityChangeTracker"
2) Отключение создания прокси-сервера избавляет от проблемы, указанной в # 1, но приводит к тому, что dbcontext не загружает дочерние объекты (например, AspNetUserLogins, которые весьма важны).
Другим решением будет доступ к контексту, созданному в контроллере. Рассмотрите стандартные методы конструктора AccountController с новым веб-приложением ASP.NET с использованием шаблона MVC (версия 5):
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
Контекст БД приложения создается, но нет доступа к нему через UserManager (поскольку свойство "Store" для UserManager).
Это не похоже на ракетную науку, поэтому я предполагаю, что я делаю что-то в основном неправильное в отношении обработки/понимания жизненного цикла dbcontext.
Итак: как правильно получить/использовать dbcontext для сохранения и обновления AspNetUsers, связанных пользовательских свойств и сохранения дочерних объектов (например, AspNetUserLogins)?
РЕДАКТИРОВАТЬ -------
Еще одна вещь, которую я пробовал...
Я обновил конструктор AccountController по умолчанию:
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
:
public AccountController(UserManager<ApplicationUser> userManager)
{
userDbContext= new UserDbContext();
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>();
UserManager<ApplicationUser> manager = new UserManager<ApplicationUser>(store);
manager.UserValidator = new CustomUserValidator<ApplicationUser>(UserManager);
// UserManager = userManager;
UserManager = manager;
}
В попытке вставить dbcontext. Позже, в теле публичного метода async Task, я пытаюсь вызвать:
var updated = await UserManager.UpdateAsync(user);
if (updated.Succeeded)
{
userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
await userDbContext.SaveChangesAsync();
}
Однако попытка обновления состояния выдает исключение:
"Уже существует сгенерированный тип прокси для типа объекта-объекта" xyz.Models.ApplicationUser ". Это происходит, когда один и тот же тип слоя объектов отображается двумя или более разными моделями в AppDomain."
Это не кажется правильным... это тот же самый dbcontext, назначенный в конструкторе.
РЕДАКТИРОВАТЬ # 2 -----
Вот модель ApplicationUser:
using Microsoft.AspNet.Identity.EntityFramework;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using System.Data.Entity;
namespace xyz.App.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string ZipCode { get; set; }
public string PasswordResetToken { get; set; }
public System.DateTime? PasswordResetTokenExpiry { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public ApplicationUser() { }
}
public class UserDbContext : IdentityDbContext<ApplicationUser>
{
public UserDbContext()
: base("DefaultConnection")
{
}
}
}
Заключительное редактирование ----------------------------
Хорошо, после некоторых комментариев и комментариев, я понял, что задал вопрос не так. Мой вопрос был действительно: как использовать сначала кодовые, а не первичные миграции баз данных. Исходя из школы Hibernate, я привык вручную сопоставлять объекты с таблицами через XML или аннотации в Java.
Итак, в skimming в этой статье я пропустил важные шаги по миграции. Извлеченный урок.