C# EF Core 2.1中的动态数据种子迁移生成取决于DbContext bool标志,在OnModelCreating()中使用 现状
您好,我有一个dotnet标准库,其中我使用efcore2.1.1(代码优先方法)访问持久层。要创建迁移,我使用一个单独的dotnet核心控制台应用程序(在同一个解决方案中),该应用程序包含一个C# EF Core 2.1中的动态数据种子迁移生成取决于DbContext bool标志,在OnModelCreating()中使用 现状,c#,entity-framework,ef-code-first,entity-framework-core,ef-core-2.1,C#,Entity Framework,Ef Code First,Entity Framework Core,Ef Core 2.1,您好,我有一个dotnet标准库,其中我使用efcore2.1.1(代码优先方法)访问持久层。要创建迁移,我使用一个单独的dotnet核心控制台应用程序(在同一个解决方案中),该应用程序包含一个IDesignTimeDbContextFactory实现。 有必要对一些数据进行种子设定,我希望以一种舒适的方式实现它,因为将来要进行种子设定的数据将被扩展或修改。因此,在implementedientitypeconfiguration中,我使用扩展方法.HasData(),它获取一个要种子化的对象数
IDesignTimeDbContextFactory
实现。有必要对一些数据进行种子设定,我希望以一种舒适的方式实现它,因为将来要进行种子设定的数据将被扩展或修改。因此,在implemented
ientitypeconfiguration
中,我使用扩展方法.HasData()
,它获取一个要种子化的对象数组。该数组将由一个单独的类(TemplateReader
)提供,该类从一个JSON文件加载对象(将在该文件中完成扩展和修改工作)。因此,可以修改JSON文件的内容并添加新的迁移,该迁移将包含要插入(modelBuilder.InsertData()
)、更新(modelBuilder.UpdateData()
)或删除(modelBuilder.DeleteData()
)语句的生成代码。由于我不会发布JSON文件,并且我希望避免加载序列化数据以进行种子设定和执行
.HasData()
,因此我希望使用构造函数将赋予DbContext
的bool
值。为了避免在不需要调用移植种子时使用bool值(以及
.HasData()
),我使用默认值false实现了一个重载构造函数。
此外,我不会使用onconfigurang
,因为我希望能够灵活地在IoC容器中设置DbContextOptions
对象或单独设置测试
代码 下面的代码包含重命名的变量,以便对项目的内容更加匿名,但表示当前实现的逻辑 MyDesignTimeDbContextFactory:
public class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
var connectionString = ConfigurationManager.ConnectionStrings["SqlServer"].ConnectionString;
var contextOptionsBuilder = new DbContextOptionsBuilder<MyDbContext>()
.UseSqlServer(connectionString);
return new MyDbContext(contextOptionsBuilder.Options, true);
}
}
public sealed class MyDbContext : DbContext
{
private readonly bool _shouldSeedData;
public DbSet<Content> Contents { get; set; }
public DbSet<Template> Templates { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options, bool shouldSeedData = false) :
base(options)
{
ChangeTracker.LazyLoadingEnabled = false;
_shouldSeedData = shouldSeedData;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("mySchema");
modelBuilder.ApplyConfiguration(new TemplateTypeConfiguration(_shouldSeedData));
base.OnModelCreating(modelBuilder);
}
}
public class TemplateTypeConfiguration : IEntityTypeConfiguration<Template>
{
private readonly bool _shouldSeedData;
public TemplateTypeConfiguration(bool shouldSeedData)
{
_shouldSeedData = shouldSeedData;
}
public void Configure(EntityTypeBuilder<Template> builder)
{
builder.Property(p => p.ModuleKey)
.IsRequired();
builder.Property(p => p.Html)
.IsRequired();
if (_shouldSeedData)
{
// reads all templates from configuration file for seeding
var templateReader = new TemplateReader(Directory.GetCurrentDirectory());
var templates = templateReader.GetTemplates().ToArray();
builder.HasData(templates);
}
}
}
公共类MyDesignTimeDbContextFactory:IDesignTimeDbContextFactory
{
公共MyDbContext CreateDbContext(字符串[]args)
{
var connectionString=ConfigurationManager.connectionString[“SqlServer”].connectionString;
var contextOptionsBuilder=new DbContextOptionsBuilder()
.UseSqlServer(connectionString);
返回新的MyDbContext(contextOptionsBuilder.Options,true);
}
}
MyDbContext:
public class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
var connectionString = ConfigurationManager.ConnectionStrings["SqlServer"].ConnectionString;
var contextOptionsBuilder = new DbContextOptionsBuilder<MyDbContext>()
.UseSqlServer(connectionString);
return new MyDbContext(contextOptionsBuilder.Options, true);
}
}
public sealed class MyDbContext : DbContext
{
private readonly bool _shouldSeedData;
public DbSet<Content> Contents { get; set; }
public DbSet<Template> Templates { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options, bool shouldSeedData = false) :
base(options)
{
ChangeTracker.LazyLoadingEnabled = false;
_shouldSeedData = shouldSeedData;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("mySchema");
modelBuilder.ApplyConfiguration(new TemplateTypeConfiguration(_shouldSeedData));
base.OnModelCreating(modelBuilder);
}
}
public class TemplateTypeConfiguration : IEntityTypeConfiguration<Template>
{
private readonly bool _shouldSeedData;
public TemplateTypeConfiguration(bool shouldSeedData)
{
_shouldSeedData = shouldSeedData;
}
public void Configure(EntityTypeBuilder<Template> builder)
{
builder.Property(p => p.ModuleKey)
.IsRequired();
builder.Property(p => p.Html)
.IsRequired();
if (_shouldSeedData)
{
// reads all templates from configuration file for seeding
var templateReader = new TemplateReader(Directory.GetCurrentDirectory());
var templates = templateReader.GetTemplates().ToArray();
builder.HasData(templates);
}
}
}
公共密封类MyDbContext:DbContext
{
私有只读bool_应为种子数据;
公共数据库集内容{get;set;}
公共数据库集模板{get;set;}
公共MyDbContext(DbContextOptions选项,bool shouldSeedData=false):
基本(选项)
{
ChangeTracker.LazyLoadingEnabled=false;
_shouldSeedData=shouldSeedData;
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
hasdaultschema(“mySchema”);
ApplyConfiguration(新的TemplateTypeConfiguration(_shouldSeedData));
基于模型创建(modelBuilder);
}
}
模板类型配置:
public class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
var connectionString = ConfigurationManager.ConnectionStrings["SqlServer"].ConnectionString;
var contextOptionsBuilder = new DbContextOptionsBuilder<MyDbContext>()
.UseSqlServer(connectionString);
return new MyDbContext(contextOptionsBuilder.Options, true);
}
}
public sealed class MyDbContext : DbContext
{
private readonly bool _shouldSeedData;
public DbSet<Content> Contents { get; set; }
public DbSet<Template> Templates { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options, bool shouldSeedData = false) :
base(options)
{
ChangeTracker.LazyLoadingEnabled = false;
_shouldSeedData = shouldSeedData;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("mySchema");
modelBuilder.ApplyConfiguration(new TemplateTypeConfiguration(_shouldSeedData));
base.OnModelCreating(modelBuilder);
}
}
public class TemplateTypeConfiguration : IEntityTypeConfiguration<Template>
{
private readonly bool _shouldSeedData;
public TemplateTypeConfiguration(bool shouldSeedData)
{
_shouldSeedData = shouldSeedData;
}
public void Configure(EntityTypeBuilder<Template> builder)
{
builder.Property(p => p.ModuleKey)
.IsRequired();
builder.Property(p => p.Html)
.IsRequired();
if (_shouldSeedData)
{
// reads all templates from configuration file for seeding
var templateReader = new TemplateReader(Directory.GetCurrentDirectory());
var templates = templateReader.GetTemplates().ToArray();
builder.HasData(templates);
}
}
}
公共类TemplateTypeConfiguration:IEntityTypeConfiguration
{
私有只读bool_应为种子数据;
公共模板类型配置(bool shouldSeedData)
{
_shouldSeedData=shouldSeedData;
}
公共void配置(EntityTypeBuilder)
{
builder.Property(p=>p.ModuleKey)
.IsRequired();
属性(p=>p.Html)
.IsRequired();
如果(_shouldSeedData)
{
//从配置文件中读取所有模板以进行种子设定
var templateReader=newtemplatereader(Directory.GetCurrentDirectory());
var templates=templateReader.GetTemplates().ToArray();
HasData(模板);
}
}
}
模板(实体):
公共类模板
{
公共int Id{get;set;}
公共字符串ModuleKey{get;set;}
公共字符串Html{get;set;}
公共虚拟ICollection内容{get;set;}
}
问题 据我所知,并且我已经测试了
OnModelCreating(ModelBuilder)
将在构造函数中设置构造函数的bool值之前被调用(\u shouldseddata=shouldsedseeddata;
)。这是因为将立即调用基本构造函数,然后调用我的构造函数。因此,\u应该将种子数据
的值设置为false
,然后将其放入模板类型配置
因此,如果我对上述JSON文件进行了任何修改,那么
Add迁移
将导致没有任何逻辑的“空”迁移
已经测试过的方法 我已经尝试将
IModelCacheKeyFactory
与自己的ModelCacheKey
对象一起使用,但没有成功。作为模板,我使用了这个
我测试的另一种方法是将\u shouldSeedData
设置为公共静态
变量,并将其从MyDesignTimeDbContextFactory
设置为true
,但在我看来,这是一个非常肮脏的解决方案,我希望避免在生产代码中实现
还可以使用DbContextOptionsBuilder
的UseModel(IModel)
扩展方法,以避免在使用所需的shouldsededata=false
创建模型和初始化TemplateTypeConfiguration
时使用。这种方法的一个缺点是有重复的代码,这些代码在TemplateTypeConfiguration
的构造函数值中会有所不同。在我看来,这就像公众的静态方法一样令人讨厌
问题:
是否有一个干净的解决方案来实现由构造函数设置\u shouldSeedData
,从而在模型创建时可以在设计时使用正确的值(true
)