.net 具有实体框架的SQL列默认值
我正在尝试使用带有默认SQL值的代码优先EF6 例如,我有一个不为null的“CreatedDate”列/属性,SQL中的默认值为“getdate() 如何在代码模型中表示这一点?目前我有:.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,我是否仍需要使用
<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);
}
您还可以使用MigrationsUp
和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.