37

我将 EntityFramework.Migrations (Beta 1) 添加到现有的 Code-First 应用程序中,该应用程序正在经历一些更改(对于迁移功能和我从我的代码优先 API 生成的表的更多微调)并遇到 GETDATE () 设想。

我已经在我的 DbContext 中使用了一个自定义初始化程序类来运行 SQL 脚本来设置一些字段并在我的数据库中创建索引。我的一些 AlterTable 脚本主要用于设置具有默认值的字段(例如某些 DateTime 字段被设置为 GETDATE())。我真的希望 EntityFramework.Migrations 对此有答案,因为您可以轻松指定 defaultValue,但到目前为止我还没有看到。

有任何想法吗?我真的希望执行以下操作会神奇地起作用。(毕竟是“魔法独角兽”)

DateCreated = c.DateTime(nullable: false, defaultValue: DateTime.Now)

不幸的是,从逻辑上讲,它将我的默认值设置Update-Database为执行命令的时间。

4

8 回答 8

97

您可以使用

DateCreated = c.DateTime(nullable: false, defaultValueSql: "GETDATE()")

用法:

public partial class MyMigration : DbMigration
{
    public override void Up()
    {
        CreateTable("dbo.Users",
            c => new
                {
                    Created = c.DateTime(nullable: false, defaultValueSql: "GETDATE()"),
                })
            .PrimaryKey(t => t.ID);
 ...

2012 年 10 月 10 日更新:

按照蒂亚戈在评论中的要求,我添加了一些额外的上下文。

上面的代码是 EF Migrations 通过Add-Migration MyMigration在包管理器控制台中作为命令运行生成的迁移文件。生成的代码基于与迁移关联的 DbContext 中的模型。答案建议您修改生成的脚本,以便在创建数据库时添加默认值。

您可以在此处阅读有关实体框架代码优先迁移的更多信息。

于 2012-01-30T11:15:16.353 回答
24

我最近在 EF6 中遇到了这个问题(因为他们还没有修复它)。我发现无需手动修改 Migration 类的最简单方法是覆盖 Configuration 类中的 CodeGenerator。

通过创建一个实现 MigrationCodeGenerator 的类,然后重写 Generate 方法,您可以遍历所有操作并应用您想要的任何修改。

完成修改后,您可以初始化 CSharpMigrationCodeGenerator 并返回其默认值。

public class ExtendedMigrationCodeGenerator : MigrationCodeGenerator
{
    public override ScaffoldedMigration Generate(string migrationId, IEnumerable<MigrationOperation> operations, string sourceModel, string targetModel, string @namespace, string className)
    {
        foreach (MigrationOperation operation in operations)
        {
            if (operation is CreateTableOperation)
            {
                foreach (var column in ((CreateTableOperation)operation).Columns)
                    if (column.ClrType == typeof(DateTime) && column.IsNullable.HasValue && !column.IsNullable.Value && string.IsNullOrEmpty(column.DefaultValueSql))
                        column.DefaultValueSql = "GETDATE()";
            }
            else if (operation is AddColumnOperation)
            {
                ColumnModel column = ((AddColumnOperation)operation).Column;

                if (column.ClrType == typeof(DateTime) && column.IsNullable.HasValue && !column.IsNullable.Value && string.IsNullOrEmpty(column.DefaultValueSql))
                    column.DefaultValueSql = "GETDATE()";
            }
        }

        CSharpMigrationCodeGenerator generator = new CSharpMigrationCodeGenerator();

        return generator.Generate(migrationId, operations, sourceModel, targetModel, @namespace, className);
    }
}

internal sealed class Configuration : DbMigrationsConfiguration<Project.Models.Context.DatabaseContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"Migrations";
        this.CodeGenerator = new ExtendedMigrationCodeGenerator();
    }
}

我希望这有帮助

于 2014-01-09T15:18:25.667 回答
15

Up您必须在设置默认值的方法中使用自定义 SQL 脚本:

Sql("ALTER TABLE TableName ADD CONSTRAINT ConstraintName DEFAULT GETDATE() FOR ColumnName");

在代码中设置默认值只允许静态值 - 没有数据库级函数。

如果您要先使用代码,无论如何在 POCO 构造函数中设置它是正确的方法。此外,如果您想为某些特殊情况在应用程序中设置值,则不能在数据库中使用默认值,因为数据库中的默认值需要DatabaseGeneratedOption.IdentityDatabaseGeneratedOption.Computed。这两个选项都允许仅在数据库中设置属性。

编辑:

由于该产品仍在开发中,我的回答不再有效。检查@gius 答案以了解通过使用实现此要求的实际方法defaultValueSql(它在 EF Migrations Beta 1 中不可用,但已添加到已包含迁移的 EF 4.3 Beta 1 中)。

于 2011-12-21T20:17:31.800 回答
6

创建迁移:

public partial class Table_Alter : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.tableName", "columnName", 
           c => c.DateTime(nullable: false, defaultValueSql: "GETDATE()"));
    }

    public override void Down()
    {
        DropColumn("dbo.tableName", "columnName");
    }
}

对于现有记录,它将设置您运行Update-Database命令的日期时间,对于新记录,它将设置创建日期时间

于 2016-07-22T10:35:54.623 回答
1

或者,如果您的实体从公共接口继承,您可以覆盖 DbContext 上的 SaveChanges 方法并在该点设置或更新属性(非常适合创建日期和上次更改日期)

于 2011-12-25T01:42:47.173 回答
1

这是最简单的方法。

首先添加 DatabaseGeneratedOption.Computed DataAnnotion到您的财产

现在您可以修改 de SqlServerMigrationSqlGenarator,覆盖 Genarate 方法并设置DefaultValueSql = "GETDATE()" or "GETUTCDATE()";

于 2015-04-17T15:12:42.167 回答
1

使用 .net 6 的实体框架,我可以通过将迁移添加到默认defaultValue时间defaultValueSql

public partial class ReportQueueAddCreatedAt : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<DateTime>(
            name: "CreatedAt",
            table: "ReportQueue",
            type: "datetime2",
            nullable: false,
            defaultValueSql: "GETDATE()");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropColumn(
            name: "CreatedAt",
            table: "ReportQueue");
    }
}
于 2021-12-06T22:48:13.207 回答
0

改进:检查约束是否存在:

Sql(@"
if not exists (
    select *
      from sys.all_columns c
      join sys.tables t on t.object_id = c.object_id
      join sys.schemas s on s.schema_id = t.schema_id
      join sys.default_constraints d on c.default_object_id = d.object_id
    where 
      d.name = 'DF_ThubOutputEmail_Created'
)
begin
    ALTER TABLE dbo.ThubOutputEmails ADD CONSTRAINT DF_ThubOutputEmail_Created default getdate() for Created;
end");
于 2016-02-17T17:26:09.940 回答