I am trying to use Code-First EF6 with default SQL values.
For example, I have a \"CreatedDate\" column/property not null with a default in SQL of \"getdate()\"
Accepted answer is correct for EF6, I'm only adding EF Core solution; (also my solution focuses on changing the default-value, rather than creating it properly the first time)
There is still no Data-Attribute in EF Core
.
And you must still use the Fluent API; it does have a HasDefaultValue
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3);
}
Note, there is also HasDefaultValueSql
for NULL case:
.HasDefaultValueSql("NULL");
And you can also use the Migrations Up
and Down
methods, you can alter the defaultValue
or defaultValueSql
but you may need to drop Indexes first. Here's an example:
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"
);
}
}
[mysql]
For those, who don't want to use computed and rewrite it after every db update, I wrote extension method for database partial class. Sure, there are thing that has to be improved or added, but for now it is enough for our using, enjoy.
Take into account, that due to database_schema access it is not the fastest and also you need to have same entity name as table name (or rewrite it somehow).
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; }
}
try with this. This code insert by default the current date
//[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Created { get; set; } = new DateTime();
Currently in EF6 there is not an attribute to define database functions used for a certain property default value. You can vote on Codeplex to get it implemented:
https://entityframework.codeplex.com/workitem/44
The accepted way to implement something like that is to use Computed
properties with Migrations
where you specify the default database function.
Your class could look like this in C#:
public class MyEntity
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Created { get; set; }
}
The computed property doesn't have to be nullable.
Then you have to run a migration and modify it by hand to include the default SQL function. A migration could look like:
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");
}
}
You will notice the defaultValueSql function. That is the key to get the computation working