简体   繁体   English

EF6 - 运行没有种子的Update-Database命令

[英]EF6 - Run Update-Database Command without seeds

I'm Using Entity Framework 6 and I'm using migrations. 我正在使用实体框架6,我正在使用迁移。 I have already created the database using an initial migration. 我已经使用初始迁移创建了数据库。 Now I have done changes to the Model and the context has changed, and I want to update the database BUT... When I try to run again the Database-Update command the seeds are also running too, and this bring errores due some data is inserted again. 现在我已对模型进行了更改并且上下文已更改,我想更新数据库但是...当我再次尝试运行Database-Update命令时,种子也在运行,这会因为一些数据而导致错误再次插入。

So, how can I to run the Update-Database command WITHOUT running the seed method? 那么,如何在不运行种子方法的情况下运行Update-Database命令?


It is hard to believe that EF doesn't have any simple option like -No-Seed for that. 很难相信EF没有像-No-Seed这样的简单选项。 I'm almost secure that other ORMs does. 其他ORM的确如此安全。

From the source code of DbMigrationsConfiguration<TContext> : 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>

Basically, you don't have another option than implement an "add or update" logic because the Seed method will be executed each time after the initializer is used. 基本上,除了实现“添加或更新”逻辑之外,没有其他选项,因为每次使用初始化程序后都会执行Seed方法。

The AddOrUpdate extension method is useful for this, but I have also used this in some cases: AddOrUpdate扩展方法对此很有用,但在某些情况下我也使用了它:

            if (!context.Entities.Any())
            {
                 // Seed
            }

From this page: Database initializer and Migrations Seed methods : 从此页面: 数据库初始化程序和迁移种子方法

The Seed method on the Configuration class runs whenever the Update-Database PowerShell command is executed. 只要执行Update-Database PowerShell命令,就会运行Configuration类上的Seed方法。 Unless the Migrations initializer is being used the Migrations Seed method will not be executed when your application starts. 除非正在使用迁移初始化程序,否则在应用程序启动时将不会执行迁移Seed方法。

So, I think you don't have many options here, the migration Seed method always will be called if you run Update-Database command. 因此,我认为您没有很多选项,如果您运行Update-Database命令,将始终调用迁移Seed方法。 I was digging if exist a parameter to this command that let you specify not run the Seed method, but I'm fraid it don't exist yet. 我正在挖掘如果存在一个参数给这个命令,让你指定不运行Seed方法,但我很沮丧它还不存在。 These are all the parameters you can use (you can find more info in this 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>]

If you are executing a sql script to insert data in the Seed method, you could use a booleam condition to avoid reinsert the same fields after the first time. 如果您正在执行sql脚本以在Seed方法中插入数据,则可以使用booleam条件来避免在第一次之后重新插入相同的字段。

As an aditional info, your request in have a parameter to avoid execute the Seed method when you run the Update-Database command already exist in this site , which is used by EF team to collect suggestions from the community. 作为附加信息,您的请求中有一个参数可以避免在运行此站点中已存在的Update-Database命令时执行Seed方法,EF团队使用该命令从社区收集建议。

I moved all my seed statements into separate methods that can be commented out easily before running 'update-database'. 我将所有种子语句移动到单独的方法中,可以在运行“update-database”之前轻松注释掉。

protected override void Seed(Tpsc.EDI.EDIContext context)
{
    try
    {
        //EDI.Seed.DoSeed(context);
    }
    catch (DbEntityValidationException e)
    {
        ...
    }
}

I usually use the command update-database -sc then I run the script generated to update database manually. 我通常使用命令update-database -sc然后我运行生成的脚本来手动更新数据库。 I didn't feel confortable to do this in the beggining, but now I like to see what is going to happen with my database before its too late. 在开始的时候,我觉得这样做并不舒服,但现在我想看看我的数据库会发生什么事,为时已晚。

If you have sql scripts to insert the data and you want to prevent future insertions, the you can user a sql merge to avoid duplicates. 如果您有sql脚本来插入数据并且您希望阻止将来插入,则可以使用sql合并来避免重复。 Insert all the data that you have in a temp table with the same structure of your target table and then use the merge to decide when you will insert the records or not. 将您拥有的所有数据插入到具有与目标表相同结构的临时表中,然后使用合并来决定何时插入记录。 If they match is because you inserted once. 如果它们匹配是因为你插入了一次。

Supposed S is your temp table with all your data and T the final table 假定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

for more references use https://technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx 有关更多参考资料,请使用https://technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx

Old question, but always useful. 老问题,但总是很有用。 So my contribute is: use ConfigurationManager options in your web.config/app.config . 所以我的贡献是: 在web.config / app.config中使用ConfigurationManager选项

This is possible as System.Configuration.ConfigurationManager is accessible from your Configuration class. 这是可能的,因为可以从Configuration类访问System.Configuration.ConfigurationManager

Do it in this way: 这样做:

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
        // ...
    }
}

In this way you can define an application setting in the web.config or app.config file: 通过这种方式,您可以在web.config或app.config文件中定义应用程序设置:

<appSettings>
  <add key="Database.Seed" value="false" />  <!-- <== do not seed! -->
  ...
</appSettings>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM