使用C# Bogus生成子数据时EF Core种子数据关联报错问题排查
解决EF Core种子数据中导航属性设置的报错问题
咱们先搞清楚为啥会出现这个错误:EF Core的种子数据是直接对应数据库记录的,它不支持通过导航属性(比如DiscussionModel.Comments)来关联实体,必须显式设置外键字段(也就是CommentModel.DiscussionId)。因为种子数据是直接写入数据库的,EF不会自动帮你把导航属性的关联转化为外键值,所以才会提示你要在CommentModel的种子数据里指定DiscussionId。
你之前的代码问题在于:生成的CommentModel没有设置DiscussionId,而且直接给DiscussionModel.Comments赋值,EF不知道这些评论属于哪个讨论,自然会报错。
正确的实现方式
我们需要先生成所有讨论,再为每个讨论生成对应的评论并绑定外键,最后分别给两个实体添加种子数据:
// 1. 先生成所有Discussion实体 int discussionId = 1; var discussions = new Faker<DiscussionModel>() .RuleFor(m => m.Id, f => discussionId++) .Generate(35); // 2. 为每个Discussion生成对应的Comment,并设置外键DiscussionId int commentId = 1; var comments = new List<CommentModel>(); foreach (var discussion in discussions) { var discussionComments = new Faker<CommentModel>() .RuleFor(m => m.Id, f => commentId++) .RuleFor(m => m.Content, f => f.Commerce.ProductDescription()) .RuleFor(m => m.DiscussionId, _ => discussion.Id) // 关键:绑定当前讨论的Id作为外键 .Generate(new Random().Next(0, 25)); comments.AddRange(discussionComments); } // 3. 分别添加种子数据,先加Discussion(保证父实体存在),再加Comment builder.Entity<DiscussionModel>().HasData(discussions); builder.Entity<CommentModel>().HasData(comments);
关于你提到的官方示例
你觉得官方示例实用性更强,可能是混淆了内存中生成关联实体和EF Core种子数据的场景。如果官方示例是展示在内存里创建关联的实体对象(比如用于测试),那直接设置导航属性是没问题的,但种子数据是要写入数据库的,必须遵循数据库的外键约束规则,所以必须显式指定外键值——这不是官方示例不准确,而是适用的场景不同。
内容的提问来源于stack exchange,提问作者Randy Hall
相关产品推荐
相关产品推荐

