.net 具有实体框架的SQL列默认值

.net 具有实体框架的SQL列默认值,.net,entity-framework,entity-framework-6,.net,Entity Framework,Entity Framework 6,我正在尝试使用带有默认SQL值的代码优先EF6 例如,我有一个不为null的“CreatedDate”列/属性,SQL中的默认值为“getdate() 如何在代码模型中表示这一点?目前我有: <DatabaseGenerated(DatabaseGeneratedOption.Computed)> Public Property CreatedDate As DateTime 公共属性CreatedDate作为日期时间 这是否可行,或者即使实际列不应为null,我是否仍需要使用

我正在尝试使用带有默认SQL值的代码优先EF6

例如,我有一个不为null的“CreatedDate”列/属性,SQL中的默认值为“getdate()

如何在代码模型中表示这一点?目前我有:

<DatabaseGenerated(DatabaseGeneratedOption.Computed)>
Public Property CreatedDate As DateTime

公共属性CreatedDate作为日期时间
这是否可行,或者即使实际列不应为null,我是否仍需要使用null,以便EF在未设置值时不发送值:

<DatabaseGenerated(DatabaseGeneratedOption.Computed)>
Public Property CreatedDate As DateTime?

公共属性CreatedDate作为日期时间?
还是有更好的解决方案


我不希望EF处理我的默认值-我知道这对我来说是可用的,但在我目前的情况下不可能实现。

目前在EF6中,没有一个属性来定义用于特定属性默认值的数据库函数。您可以对Codeplex进行投票以实现它:

实现类似功能的公认方法是将
Computed
属性与
Migrations
一起使用,其中指定默认的数据库功能

你的班级在C#中可能是这样的:

computed属性不必为null

然后,您必须运行迁移并手动修改它以包含默认的SQL函数。迁移可能看起来像:

public partial class Initial : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.MyEntities",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(),
                    Created = c.DateTime(nullable: false, defaultValueSql: "GetDate()"),
                })
            .PrimaryKey(t => t.Id);

    }

    public override void Down()
    {
        DropTable("dbo.MyEntities");
    }
}

您将注意到defaultValueSql函数。这是使计算工作正常的关键

公认的答案对于EF6是正确的,我只是在添加解决方案;(另外,我的解决方案侧重于更改默认值,而不是第一次正确创建它)

EF-Core
中仍然没有数据属性

您必须仍然使用Fluent API;它确实有一个
hasdaultvalue

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Rating)
        .HasDefaultValue(3);
}
您还可以使用Migrations
Up
Down
方法,您可以更改
defaultValue
defaultValueSql
,但可能需要先删除索引。下面是一个例子:

public partial class RemovingDefaultToZeroPlantIdManualChange : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME"
        );

        migrationBuilder.AlterColumn<int>(
            name: "COLUMN_NAME",
            table: "TABLE_NAME",
            nullable: true,
            //note here, in the Up method, I'm specifying a new defaultValue:
            defaultValueSql: "NULL",
            oldClrType: typeof(int));

        migrationBuilder.CreateIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME",
            column: "COLUMN_NAME"
        );
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME"
        );

        migrationBuilder.AlterColumn<int>(
            name: "COLUMN_NAME",
            table: "TABLE_NAME",
            nullable: true,
            //note here, in the Down method, I'll restore to the old defaultValue:
            defaultValueSql: "0",
            oldClrType: typeof(int));

        migrationBuilder.CreateIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME",
            column: "COLUMN_NAME"
        );


    }
}
公共部分类RemovingDefaultToZeroPlantIdManualChange:迁移
{
受保护的覆盖作废(MigrationBuilder MigrationBuilder)
{
migrationBuilder.DropIndex(
名称:“IX_表\u名称\u列\u名称”,
表:“表名称”
);
migrationBuilder.AlterColumn(
名称:“列名称”,
表格:“表格名称”,
可为空:是的,
//注意,在Up方法中,我指定了一个新的defaultValue:
defaultValueSql:“NULL”,
oldcltype:typeof(int));
migrationBuilder.CreateIndex(
名称:“IX_表\u名称\u列\u名称”,
表格:“表格名称”,
列:“列名称”
);
}
受保护的覆盖无效关闭(MigrationBuilder MigrationBuilder)
{
migrationBuilder.DropIndex(
名称:“IX_表\u名称\u列\u名称”,
表:“表名称”
);
migrationBuilder.AlterColumn(
名称:“列名称”,
表格:“表格名称”,
可为空:是的,
//注意,在Down方法中,我将恢复到旧的defaultValue:
defaultValueSql:“0”,
oldcltype:typeof(int));
migrationBuilder.CreateIndex(
名称:“IX_表\u名称\u列\u名称”,
表格:“表格名称”,
列:“列名称”
);
}
}

试试这个。此代码默认插入当前日期

//[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Created { get; set; } = new DateTime();
[mysql]

对于那些不想在每次数据库更新后使用computed并重写它的人,我为数据库分部类编写了扩展方法。当然,还有一些东西需要改进或补充,但现在已经足够我们使用了,享受吧

考虑到,由于数据库模式访问的原因,它不是最快的,而且您还需要具有与表名相同的实体名(或者以某种方式重写它)

公共静态bool GetDBDefaults(对象实体)
{
尝试
{
字符串表_name=entity.GetType().name;
字符串q=$“从信息模式中选择列名称、列默认值。列默认值不为空且表模式不在的列('information_schema'、'sys'、'performance_schema'、'mysql')和表名称='{table_name}'按表模式、表名称、序号位置排序;”;
List dbDefaults=new List();
使用(DatabaseModelFull db=newdatabasemodelfull())
{
dbDefaults=db.Database.SqlQuery(q.ToList();
}
类型myType=entity.GetType();
IList props=新列表(myType.GetProperties());
IList fields=新列表(myType.GetFields());
foreach(dbDefaults中的var dbDefault)
{
var prop=props.SingleOrDefault(x=>x.Name==dbDefault.column\u Name);
如果(prop!=null)
{
if(dbDefault.column\u default.Equals(“当前时间戳”))
prop.SetValue(entity,System.Convert.ChangeType(DateTime.Now,prop.PropertyType));
其他的
prop.SetValue(entity,System.Convert.ChangeType(dbDefault.column_default,prop.PropertyType));
继续;
}
var field=fields.SingleOrDefault(x=>x.Name==dbDefault.column\u Name);
如果(字段!=null)
{
if(dbDefault.column\u default.Equals(“当前时间戳”))
field.SetValue(entity,System.Convert.ChangeType(DateTime.Now,field.FieldType));
其他的
field.SetValue(entity,System.Convert.ChangeType(dbDefault.column_default,field.FieldType));
}
}
返回true;
}
抓住
{
返回false;
}
}
公共类DBDefaults
{
公共字符串列_name{get;set;}
公共字符串列\u默认值{get;set;}
}
添加此
public partial class RemovingDefaultToZeroPlantIdManualChange : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME"
        );

        migrationBuilder.AlterColumn<int>(
            name: "COLUMN_NAME",
            table: "TABLE_NAME",
            nullable: true,
            //note here, in the Up method, I'm specifying a new defaultValue:
            defaultValueSql: "NULL",
            oldClrType: typeof(int));

        migrationBuilder.CreateIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME",
            column: "COLUMN_NAME"
        );
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME"
        );

        migrationBuilder.AlterColumn<int>(
            name: "COLUMN_NAME",
            table: "TABLE_NAME",
            nullable: true,
            //note here, in the Down method, I'll restore to the old defaultValue:
            defaultValueSql: "0",
            oldClrType: typeof(int));

        migrationBuilder.CreateIndex(
            name: "IX_TABLE_NAME_COLUMN_NAME",
            table: "TABLE_NAME",
            column: "COLUMN_NAME"
        );


    }
}
//[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Created { get; set; } = new DateTime();
    public static bool GetDBDefaults(object entity)
    {
        try
        {
            string table_name = entity.GetType().Name;

            string q = $"select column_name, column_default from information_schema.columns where column_default is not null and table_schema not in ('information_schema', 'sys', 'performance_schema', 'mysql') and table_name = '{table_name}' order by table_schema, table_name, ordinal_position;";

            List<DBDefaults> dbDefaults = new List<DBDefaults>();
            using (DatabaseModelFull db = new DatabaseModelFull())
            {
                dbDefaults = db.Database.SqlQuery<DBDefaults>(q).ToList();
            }

            Type myType = entity.GetType();
            IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
            IList<FieldInfo> fields = new List<FieldInfo>(myType.GetFields());

            foreach (var dbDefault in dbDefaults)
            {
                var prop = props.SingleOrDefault(x => x.Name == dbDefault.column_name);

                if (prop != null)
                {
                    if (dbDefault.column_default.Equals("CURRENT_TIMESTAMP"))
                        prop.SetValue(entity, System.Convert.ChangeType(DateTime.Now, prop.PropertyType));
                    else
                        prop.SetValue(entity, System.Convert.ChangeType(dbDefault.column_default, prop.PropertyType));
                    continue;
                }

                var field = fields.SingleOrDefault(x => x.Name == dbDefault.column_name);

                if (field != null)
                {
                    if (dbDefault.column_default.Equals("CURRENT_TIMESTAMP"))
                        field.SetValue(entity, System.Convert.ChangeType(DateTime.Now, field.FieldType));
                    else
                        field.SetValue(entity, System.Convert.ChangeType(dbDefault.column_default, field.FieldType));
                }
            }
            return true;
        }
        catch
        {
            return false;
        }
    }


    public class DBDefaults
    {
        public string column_name { get; set; }
        public string column_default { get; set; }
    }
// Item database declaration
public Item()
{
    public string id { get; set; }
    public string description { get; set }
}

// Add item to database code.  First one uses the default value, the second is
// overriding it using the specified value.  Anything inside brackets uses your
// database context and class definition objects.
var itemToAdd1 = new [dbClass].Item
{
    id = "CodeTest1"
};
var itemToAdd2 = new new[DBClass].Item
{
    id = "CodeTest2",
    description = "Default value override in code"
};
[dbContext].Add(itemToAdd1);
[dbContext].Add(itemToAdd2);
[dbContext].SaveChanges();


// The behavior changes based on the DatabaseGeneratedOption setting on the database
// class definition for the description property.

// DatabaseGeneratedOption:  None
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string description { get; set; }

Result:
id = "CodeTest1",                                   // First item, using default value
description = NULL                                  // Code sent null value and SQL used it instead of the default

id = "CodeTest2",                                   // Second item, overriding description in code
description = "Default value override in code"      // Code override value was used by SQL as expected


// DatabaseGeneratedOption:  Identity
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string description { get; set; }

Result:
id = "CodeTest1",                                   // First item, using default value
description = "SQL Default Value"                   // Code did not send any value and SQL used the DB default value as expected

id = "CodeTest2",                                   // Second item, overriding description in code
description = "Default value override in code"      // Code override value was used by SQL as expected


// DatabaseGeneratedOption:  Computed
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string description { get; set; }

Result:
id = "CodeTest1",                                   // First item, using default value
description = "SQL Default Value"                   // Code did not send any value and SQL used the DB default value as expected

id = "CodeTest2",                                   // Second item, overriding description in code
description = "SQL Default Value"                   // The SQL default value was still used despite setting this property in code.