EF6 - 在没有种子的情况下运行更新数据库命令
Posted
技术标签:
【中文标题】EF6 - 在没有种子的情况下运行更新数据库命令【英文标题】:EF6 - Run Update-Database Command without seeds 【发布时间】:2015-04-22 12:13:51 【问题描述】:我正在使用 Entity Framework 6 并且正在使用迁移。我已经使用初始迁移创建了数据库。现在我已经对模型进行了更改,上下文也发生了变化,我想更新数据库但是......
当我尝试再次运行Database-Update
命令时,种子也在运行,这会由于再次插入一些数据而带来错误。
那么,如何在不运行种子方法的情况下运行Update-Database
命令?
很难相信 EF 没有像 -No-Seed
这样的简单选项。我几乎与其他 ORM 一样安全。
【问题讨论】:
你使用的是AddOrUpdate
扩展方法吗?
不,我没有使用AddOrUpdate
进行所有种子插入,除了原始的 slq 脚本。
***.com/a/20245687/150342
同意,这是缺失的,并不是因为我们做错了什么,EF 的 update-database 命令只是缺少一个 [no-seed] 参数。有时我想通过不需要重新播种数据的迁移来匆忙通过 3 或 4 个环境。我们的种子方法可能需要 2-3 分钟才能针对我们的远程数据库运行。 : (
【参考方案1】:
来自DbMigrationsConfiguration<TContext>
的源码:
/// <summary>
/// Runs after upgrading to the latest migration to allow seed data to be updated.
///
/// </summary>
///
/// <remarks>
/// Note that the database may already contain seed data when this method runs. This means that
/// implementations of this method must check whether or not seed data is present and/or up-to-date
/// and then only make changes if necessary and in a non-destructive way. The
/// <see cref="M:System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate``1(System.Data.Entity.IDbSet``0,``0[])"/>
/// can be used to help with this, but for seeding large amounts of data it may be necessary to do less
/// granular checks if performance is an issue.
/// If the <see cref="T:System.Data.Entity.MigrateDatabaseToLatestVersion`2"/> database
/// initializer is being used, then this method will be called each time that the initializer runs.
/// If one of the <see cref="T:System.Data.Entity.DropCreateDatabaseAlways`1"/>, <see cref="T:System.Data.Entity.DropCreateDatabaseIfModelChanges`1"/>,
/// or <see cref="T:System.Data.Entity.CreateDatabaseIfNotExists`1"/> initializers is being used, then this method will not be
/// called and the Seed method defined in the initializer should be used instead.
///
/// </remarks>
/// <param name="context">Context to be used for updating seed data. </param>
基本上,除了实现“添加或更新”逻辑之外,您别无选择,因为每次使用初始化程序后都会执行 Seed 方法。
AddOrUpdate 扩展方法对此很有用,但我在某些情况下也使用过:
if (!context.Entities.Any())
// Seed
【讨论】:
是的...我要继续删除我写一半的答案,因为您的代码示例正是我所写的:)... +1 如果没有待处理的迁移就不会执行 Seed 方法是完全错误的 @Colin 你是对的。在执行“migrator.Update()”之前,我的代码“if (migrator.GetPendingMigrations().Any())”中有这个。我正在更新我的答案。谢谢你。【参考方案2】:从此页面:Database initializer and Migrations Seed methods:
Configuration
类上的Seed
方法在Update-Database
PowerShell 时运行 命令被执行。除非正在使用 Migrations 初始化程序 当你的应用程序不会执行 MigrationsSeed
方法 开始。
所以,我认为你在这里没有太多选择,如果你运行Update-Database
命令,迁移Seed
方法总是会被调用。我正在挖掘是否存在此命令的参数,让您指定不运行 Seed
方法,但我担心它还不存在。这些是您可以使用的所有参数(您可以在此link 中找到更多信息):
Update-Database [-SourceMigration <String>] [-TargetMigration <String>] [-Script] [-Force]
[-ProjectName <String>] [-StartUpProjectName <String>] [-ConfigurationTypeName <String>]
[-ConnectionStringName <String>] [-AppDomainBaseDirectory <String>] [<CommonParameters>]
Update-Database [-SourceMigration <String>] [-TargetMigration <String>] [-Script] [-Force]
[-ProjectName <String>] [-StartUpProjectName <String>] [-ConfigurationTypeName <String>]
-ConnectionString <String> -ConnectionProviderName <String>
[-AppDomainBaseDirectory <String>] [<CommonParameters>]
如果您正在执行 sql 脚本以在 Seed
方法中插入数据,则可以使用布尔条件来避免在第一次之后重新插入相同的字段。
作为附加信息,您的请求中有一个参数,以避免在您运行Update-Database
命令时执行Seed
方法,此site 中已经存在,EF 团队使用该参数收集来自社区的建议.
【讨论】:
【参考方案3】:我将所有种子语句移动到单独的方法中,这些方法可以在运行“更新数据库”之前轻松注释掉。
protected override void Seed(Tpsc.EDI.EDIContext context)
try
//EDI.Seed.DoSeed(context);
catch (DbEntityValidationException e)
...
【讨论】:
【参考方案4】:如果您有用于插入数据的 sql 脚本,并且您想防止以后再插入,您可以使用 sql 合并 来避免重复。将所有数据插入到与目标表结构相同的临时表中,然后使用合并来决定何时插入记录。如果它们匹配是因为您插入了一次。
假设 S 是包含所有数据的临时表,而 T 是最终表
MERGE Target AS T
USING Source AS S
ON (T.EmployeeID = S.EmployeeID AND T.EmployeeName LIKE 'S%'
AND S.EmployeeName LIKE 'S%' )
WHEN NOT MATCHED BY TARGET
THEN INSERT(EmployeeID, EmployeeName) VALUES(S.EmployeeID, S.EmployeeName)
WHEN MATCHED
THEN UPDATE SET T.EmployeeName = S.EmployeeName
WHEN NOT MATCHED BY SOURCE
THEN DELETE
更多参考请使用https://technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx
【讨论】:
【参考方案5】:我通常使用命令update-database -sc
然后运行生成的脚本来手动更新数据库。
一开始我觉得这样做不太舒服,但现在我想在为时已晚之前看看我的数据库会发生什么。
【讨论】:
【参考方案6】:老问题,但总是有用的。所以我的贡献是:在您的 web.config/app.config 中使用 ConfigurationManager 选项。
这是可能的,因为 System.Configuration.ConfigurationManager
可以从您的 Configuration 类中访问。
这样做:
public sealed class Configuration : DbMigrationsConfiguration<Booking.EntityFramework.BookingDbContext>
public Configuration()
// ...
protected override void Seed(Booking.EntityFramework.BookingDbContext context)
// check configuration if seed must be skipped
if (!bool.Parse(ConfigurationManager.AppSettings["Database.Seed"] ?? bool.TrueString)) return;
// if here, seed your database
// ...
通过这种方式,您可以在 web.config 或 app.config 文件中定义应用程序设置:
<appSettings>
<add key="Database.Seed" value="false" /> <!-- <== do not seed! -->
...
</appSettings>
【讨论】:
以上是关于EF6 - 在没有种子的情况下运行更新数据库命令的主要内容,如果未能解决你的问题,请参考以下文章