我正在学习ASP.NET,并且在我的项目中使用EF核心。在运行迁移时,我想添加一些测试数据。下面是我的AppDbContext类和模型类:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Game> Games { get; set; }
public DbSet<Studio> Studios { get; set; }
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var converter = new EnumToNumberConverter<Genre, byte>();
builder.Entity<Game>().Property(item => item.Genre).HasConversion(converter);
}
}
public class Person
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(30)]
public string Name { get; set; }
[Required]
[StringLength(30)]
public string Surname { get; set; }
}
public class Game
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[Range(0.0, 1000.0)]
public double Price { get; set; }
public Genre Genre { get; set; }
[Required]
public Studio Studio { get; set; }
}
public class Studio
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public IEnumerable<Game> Games { get; set; }
[Required]
public decimal Budget { get; set; }
public IEnumerable<Person> Employees { get; set; }
}正如你所注意到的,在游戏和工作室实体之间有一个有点复杂的关系。游戏不仅有制作游戏的工作室,而且有他们开发的游戏列表。
如果我必须编写OnModelCreating方法,我将首先创建一些测试人员,然后使用它们来填充Studio类中的Employees字段。当我不得不创建游戏时,问题就会发生。工作室还不存在,如果我想先创建工作室,游戏是一个缺失的元素。
我必须手动创建一些游戏,忽略Studio引用,然后实例化工作室,然后手动将对象链接到一起,还是有更好的解决方案?诚挚的问候。
发布于 2019-12-26 20:52:04
也许是因为人们只读了标题,但是大家都跳到了如何在实体框架中播种的问题上。接下来,一些人提出了EF核中不存在的AddOrUpdate。
EF核中的种子与EF6相比发生了巨大的变化。在EF6的Seed方法中,可以保存对象图,即包含引用和集合的对象。但是,AddOrUpdate方法有几个问题(我不会在这里详细说明它们),这使得它的行为很难跟踪,甚至如果您没有意识到它们,甚至很难纠正它们。
作为对此的(结束)反应,EF团队决定不再让EF决定是否应该添加或更新一个实体。种子应该添加一个实体,如果它是不存在的,或者不做任何其他的事情。永远不要更新。这些考虑因素大大简化了EF核心的播种机制:
IDENTITY INSERT ON键中也应该是硬的),coded.这意味着您必须将StudioId添加到Game中。StudioId和GenreId到Person。不支持独立的关联(没有StudioId的StudioId引用)。(我认为这是一个意义深远的建筑决定)。
这样做,您的种子代码(稍微简化了一点)可能如下所示:
var games = new[]
{
new Game{ Id = 1, Name = "Game1", StudioId = 1 },
new Game{ Id = 2, Name = "Game2", StudioId = 1 },
};
var studio = new Studio
{
Id = 1,
Name = "Studio1",
};
modelBuilder.Entity<Studio>().HasData(studio);
modelBuilder.Entity<Game>().HasData(games);循环引用Studio⟷Game在这里并不重要,因为它只代表一个外键。
然而,对两个外键的循环引用是不可能的。假设Studio具有由DirectorId引用的Person类型的Director属性,并且董事也是雇员:
var director = new Person { Id = 1, Name = "Director1", StudioId = 1 }; // Employee of Studio1
var studio = new Studio
{
Id = 1,
Name = "Studio1",
DirectorId = 1 // Director is "Director1"
};现在出现了一个鸡与蛋问题:只有先插入另一个实体,才能插入两个实体。
InvalidOperationException:无法保存更改,因为要保存的数据中检测到循环依赖项。
我认为这是这个设计决定的另一个深远后果。在EF6中,即使它的AddOrUpdate瘫痪了,至少也可以调用SaveChanges两次来适应这种情况。
考虑到最重要的是,种子不是迁移友好的,我对数据播种的立场是:要么不支持它(我不介意),要么支持它。
发布于 2019-12-25 13:33:03
您应该使用ModelBuilder来种子数据:
modelBuilder.Entity<Post>().HasData(
new Post() { BlogId = 1, PostId = 1, Title = "First post", Content = "Test 1" });发布于 2019-12-25 13:25:40
protected override async void Seed(ApplicationContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
context.Test.AddOrUpdate(x => x.Id,
new Test() { Id = 1, Name = "Test" }
);
await context.SaveChangesAsync();
}在PM中插入: 1.启用-移动2.添加-迁移初始3.更新-数据库
https://stackoverflow.com/questions/59478797
复制相似问题