У меня есть «довольно стандартная» 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, но я боюсь, что я не мог заставить это работать, поскольку это выдало ошибку.
Может кто-нибудь определить, где у меня случайно есть два контекста, или определить проблему?
Большое спасибо.