为什么 Entity Framework 在我尝试关联现有实体时会创建一个新实体?
Why does Entity Framework create a new entity when I try to associate an existing one?
我有一个多对多关系(用户到技能),当我尝试将现有技能与用户相关联时,它总是会创建一个新技能。
用户:
public class ApplicationUser : IdentityUser
{
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 virtual ICollection<Skill> Skills { get; set; }
}
技能:
public class Skill
{
public int Id { get; set; }
public string Name { get; set; }
}
创建模型时:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>()
.HasMany<Skill>(user => user.Skills)
.WithMany();
}
正在创建协会:
public ActionResult Skills(SkillsViewModel viewModel)
{
var user = UserManager.FindById(User.Identity.GetUserId());
if(!string.IsNullOrWhiteSpace(viewModel.NewSkill)
&& !user.Skills
.Where(sk => sk.Name == viewModel.NewSkill)
.Any())
{
var foundSkill = this.db.Skills
.Where(sk => sk.Name == viewModel.NewSkill)
.FirstOrDefault();
if(foundSkill != null)
{
user.Skills.Add(foundSkill);
}
else
{
user.Skills.Add(new Skill()
{
Name = viewModel.NewSkill
});
}
}
if(viewModel.SelectedSkillId > 0)
{
var foundSkill = this.db.Skills.Find(viewModel.SelectedSkillId);
user.Skills.Add(foundSkill);
}
this.UserManager.Update(user);
return RedirectToAction("skills");
}
我已经通过并验证了我确实从数据库中得到了 'foundSkill',但是在我将其添加到用户并保存用户之后,与用户关联的技能不是我找到的那个,但是一个同名不同 ID 的新的。
我明白了。 UserManager 正在加载一个 DbContext,而我试图关联从另一个 DbContext 加载的技能。
快速测试和修复此问题是从与技能相同的 DbContext 加载用户,更新用户,保存 DbContext。
长期解决方案是确保每个请求都使用相同的 DbContext。
我有一个多对多关系(用户到技能),当我尝试将现有技能与用户相关联时,它总是会创建一个新技能。
用户:
public class ApplicationUser : IdentityUser
{
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 virtual ICollection<Skill> Skills { get; set; }
}
技能:
public class Skill
{
public int Id { get; set; }
public string Name { get; set; }
}
创建模型时:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>()
.HasMany<Skill>(user => user.Skills)
.WithMany();
}
正在创建协会:
public ActionResult Skills(SkillsViewModel viewModel)
{
var user = UserManager.FindById(User.Identity.GetUserId());
if(!string.IsNullOrWhiteSpace(viewModel.NewSkill)
&& !user.Skills
.Where(sk => sk.Name == viewModel.NewSkill)
.Any())
{
var foundSkill = this.db.Skills
.Where(sk => sk.Name == viewModel.NewSkill)
.FirstOrDefault();
if(foundSkill != null)
{
user.Skills.Add(foundSkill);
}
else
{
user.Skills.Add(new Skill()
{
Name = viewModel.NewSkill
});
}
}
if(viewModel.SelectedSkillId > 0)
{
var foundSkill = this.db.Skills.Find(viewModel.SelectedSkillId);
user.Skills.Add(foundSkill);
}
this.UserManager.Update(user);
return RedirectToAction("skills");
}
我已经通过并验证了我确实从数据库中得到了 'foundSkill',但是在我将其添加到用户并保存用户之后,与用户关联的技能不是我找到的那个,但是一个同名不同 ID 的新的。
我明白了。 UserManager 正在加载一个 DbContext,而我试图关联从另一个 DbContext 加载的技能。
快速测试和修复此问题是从与技能相同的 DbContext 加载用户,更新用户,保存 DbContext。
长期解决方案是确保每个请求都使用相同的 DbContext。