如何在 Entity Framework 应用程序中植入 IdentityUser 引用?

How do I seed IdentityUser references in an Entity Framework application?

我有一个使用 ASP.NET Identity 2.2 的 Entity Framework 应用程序(即,我的上下文继承自 IdentityDbContext<T> 并且我有一个 User class 继承来自 IdentityUser)。我在我的种子方法中使用以下调用成功地为 AspNetUsers table 播种:

var testUser = new User() {
  UserName = "TestUser",
  Email = "TestUser@Domain.tld"
};

manager.Create(testUser, "TestPassword");

我已扩展模型以包含 Post class,其中包含对我的 User class:

的引用
public class Post {

  public Post() {}

  [Required]
  public int Id { get; set; }

  [Required]
  public User User { get; set; }

}

当然,这对应于我的 User class 中的以下内容:

public class User : IdentityUser {

  public User() : base() {
    this.Posts = new HashSet<Post>();
  }

  public ICollection<Post> Posts { get; set; }

  //Additional members...
}

然后我在 Posts 集合中播种以下内容:

 var testPost = new Post() { Id = 1, User = testUser };

 context.Posts.AddOrUpdate(
   post => post.Id,
   testPost
 );

从技术上讲,这工作正常; Post 实例已创建,自动生成的 User_Id 字段已正确填充新创建的 User 实例的 Id

所以问题是什么?每次运行时,我都会在 EntityValidationErrors 中得到以下内容:"The User field is required"。它不会阻止我的应用程序正常工作,但会增加检测合法错误的难度。

显然,我可以将自定义代码添加到我的 DbContext.SaveChanges() 方法中以忽略此错误,但我宁愿首先理解为什么会发生这种情况,尤其是当我的操作方式出现问题时我正在播种我的数据。

似乎在调用 UserManager.Create() 方法时,它不会使用创建引用所需的信息更新 User 实例。我的假设是它没有填充 Id 字段,但我还没有确认。

无论如何,解决方案是在调用 UserManager.Create() 后重新加载用户。我的最终代码类似于:

var manager = new UserManager<User>(new UserStore<User>(context));

var testUser = new User() {
  UserName = "TestUser",
  Email = "TestUser@Domain.tld"
};

if (manager.Users.Count<User>() == 0) {
  manager.Create(testUser, "TestPassword");
}

testUser = (User)manager
  .Users
  .Where<User>(u => u.UserName == "TestUser")
  .FirstOrDefault<User>();

然后我可以像以前一样为 Post 记录播种:

var testPost = new Post() { Id = 1, User = testUser };

context.Posts.AddOrUpdate(
  post => post.Id,
  testPost
);    

Note: If using a [ForeignKey] attribute, it is apparently necessary to assign the User by Id (e.g., UserId = testUser.Id) instead of by object reference (e.g., User = testUser).

在我的实际应用程序中,这一切都被改组为 CreateUser() 辅助方法,因此很容易创建多个测试用户,但这涵盖了基础知识。这也解决了我原始代码中的一个缺陷,因为我之前没有检查以确定用户是否已经创建。