[entity-framework] Entity Framework 6 Code first Default value

is there "elegant" way to give specific property a default value ?

Maybe by DataAnnotations, something like :

[DefaultValue("true")]
public bool Active { get; set; }

Thank you.

This question is related to entity-framework ef-code-first default-value

The answer is


In EF core released 27th June 2016 you can use fluent API for setting default value. Go to ApplicationDbContext class, find/create the method name OnModelCreating and add the following fluent API.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
        .Property(b => b.Active)
        .HasDefaultValue(true);
}

Your model properties don't have to be 'auto properties' Even though that is easier. And the DefaultValue attribute is really only informative metadata The answer accepted here is one alternative to the constructor approach.

public class Track
{

    private const int DEFAULT_LENGTH = 400;
    private int _length = DEFAULT_LENGTH;
    [DefaultValue(DEFAULT_LENGTH)]
    public int LengthInMeters {
        get { return _length; }
        set { _length = value; }
    }
}

vs.

public class Track
{
    public Track()
    {
        LengthInMeters = 400;   
    }

    public int LengthInMeters { get; set; }        
}

This will only work for applications creating and consuming data using this specific class. Usually this isn't a problem if data access code is centralized. To update the value across all applications you need to configure the datasource to set a default value. Devi's answer shows how it can be done using migrations, sql, or whatever language your data source speaks.


You can do it by manually edit code first migration:

public override void Up()
{    
   AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
} 

Set the default value for the column in table in MSSQL Server, and in class code add attribute, like this:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

for the same property.


Just Overload the default constructor of Model class and pass any relevant parameter which you may or may not use. By this you can easily supply default values for attributes. Below is an example.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Aim.Data.Domain
{
    [MetadataType(typeof(LoginModel))]
    public partial class Login
    {       
        public Login(bool status)
        {
            this.CreatedDate = DateTime.Now;
            this.ModifiedDate = DateTime.Now;
            this.Culture = "EN-US";
            this.IsDefaultPassword = status;
            this.IsActive = status;
            this.LoginLogs = new HashSet<LoginLog>();
            this.LoginLogHistories = new HashSet<LoginLogHistory>();
        }


    }

    public class LoginModel
    {

        [Key]
        [ScaffoldColumn(false)] 
        public int Id { get; set; }
        [Required]
        public string LoginCode { get; set; }
        [Required]
        public string Password { get; set; }
        public string LastPassword { get; set; }     
        public int UserGroupId { get; set; }
        public int FalseAttempt { get; set; }
        public bool IsLocked { get; set; }
        public int CreatedBy { get; set; }       
        public System.DateTime CreatedDate { get; set; }
        public Nullable<int> ModifiedBy { get; set; }      
        public Nullable<System.DateTime> ModifiedDate { get; set; }       
        public string Culture { get; set; }        
        public virtual ICollection<LoginLog> LoginLogs { get; set; }
        public virtual ICollection<LoginLogHistory> LoginLogHistories { get; set; }
    }

}

In .NET Core 3.1 you can do the following in the model class:

    public bool? Active { get; set; } 

In the DbContext OnModelCreating you add the default value.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Foundation>()
            .Property(b => b.Active)
            .HasDefaultValueSql("1");

        base.OnModelCreating(modelBuilder);
    }

Resulting in the following in the database

enter image description here

Note: If you don't have nullable (bool?) for you property you will get the following warning

The 'bool' property 'Active' on entity type 'Foundation' is configured with a database-generated default. This default will always be used for inserts when the property has the value 'false', since this is the CLR default for the 'bool' type. Consider using the nullable 'bool?' type instead so that the default will only be used for inserts when the property value is 'null'.

The above answers really helped, but only delivered part of the solution. The major issue is that as soon as you remove the Default value attribute, the constraint on the column in database won't be removed. So previous default value will still stay in the database.

Here is a full solution to the problem, including removal of SQL constraints on attribute removal. I am also re-using .NET Framework's native DefaultValue attribute.

Usage

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }

For this to work you need to update IdentityModels.cs and Configuration.cs files

IdentityModels.cs file

Add/update this method in your ApplicationDbContext class

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
            base.OnModelCreating(modelBuilder);
            var convention = new AttributeToColumnAnnotationConvention<DefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.SingleOrDefault().Value.ToString());
            modelBuilder.Conventions.Add(convention);
}

Configuration.cs file

Update your Configuration class constructor by registering custom Sql generator, like this:

internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
    public Configuration()
    {
        // DefaultValue Sql Generator
        SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator());
    }
}

Next, add custom Sql generator class (you can add it to the Configuration.cs file or a separate file)

internal class DefaultValueSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    private int dropConstraintCount;

    protected override void Generate(AddColumnOperation addColumnOperation)
    {
        SetAnnotatedColumn(addColumnOperation.Column, addColumnOperation.Table);
        base.Generate(addColumnOperation);
    }

    protected override void Generate(AlterColumnOperation alterColumnOperation)
    {
        SetAnnotatedColumn(alterColumnOperation.Column, alterColumnOperation.Table);
        base.Generate(alterColumnOperation);
    }

    protected override void Generate(CreateTableOperation createTableOperation)
    {
        SetAnnotatedColumns(createTableOperation.Columns, createTableOperation.Name);
        base.Generate(createTableOperation);
    }

    protected override void Generate(AlterTableOperation alterTableOperation)
    {
        SetAnnotatedColumns(alterTableOperation.Columns, alterTableOperation.Name);
        base.Generate(alterTableOperation);
    }

    private void SetAnnotatedColumn(ColumnModel column, string tableName)
    {
        if (column.Annotations.TryGetValue("SqlDefaultValue", out var values))
        {
            if (values.NewValue == null)
            {
                column.DefaultValueSql = null;
                using var writer = Writer();

                // Drop Constraint
                writer.WriteLine(GetSqlDropConstraintQuery(tableName, column.Name));
                Statement(writer);
            }
            else
            {
                column.DefaultValueSql = (string)values.NewValue;
            }
        }
    }

    private void SetAnnotatedColumns(IEnumerable<ColumnModel> columns, string tableName)
    {
        foreach (var column in columns)
        {
            SetAnnotatedColumn(column, tableName);
        }
    }

    private string GetSqlDropConstraintQuery(string tableName, string columnName)
    {
        var tableNameSplitByDot = tableName.Split('.');
        var tableSchema = tableNameSplitByDot[0];
        var tablePureName = tableNameSplitByDot[1];

        var str = $@"DECLARE @var{dropConstraintCount} nvarchar(128)
SELECT @var{dropConstraintCount} = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'{tableSchema}.[{tablePureName}]')
AND col_name(parent_object_id, parent_column_id) = '{columnName}';
IF @var{dropConstraintCount} IS NOT NULL
EXECUTE('ALTER TABLE {tableSchema}.[{tablePureName}] DROP CONSTRAINT [' + @var{dropConstraintCount} + ']')";

        dropConstraintCount++;
        return str;
    }
}

What I did, I initialized values in the constructor of the entity

Note: DefaultValue attributes won't set the values of your properties automatically, you have to do it yourself


Lets consider you have a class name named Products and you have a IsActive field. just you need a create constructor :

Public class Products
{
    public Products()
    {
       IsActive = true;
    }
 public string Field1 { get; set; }
 public string Field2 { get; set; }
 public bool IsActive { get; set; }
}

Then your IsActive default value is True!

Edite :

if you want to do this with SQL use this command :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.IsActive)
        .HasDefaultValueSql("true");
}

It's been a while, but leaving a note for others. I achieved what is needed with an attribute and I decorated my model class fields with that attribute as I want.

[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }

Got the help of these 2 articles:

What I did:

Define Attribute

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
    public string DefaultValue { get; set; }
}

In the "OnModelCreating" of the context

modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));

In the custom SqlGenerator

private void SetAnnotatedColumn(ColumnModel col)
{
    AnnotationValues values;
    if (col.Annotations.TryGetValue("SqlDefaultValue", out values))
    {
         col.DefaultValueSql = (string)values.NewValue;
    }
}

Then in the Migration Configuration constructor, register the custom SQL generator.

SetSqlGenerator("System.Data.SqlClient", new CustomMigrationSqlGenerator());

I admit that my approach escapes the whole "Code First" concept. But if you have the ability to just change the default value in the table itself... it's much simpler than the lengths that you have to go through above... I'm just too lazy to do all that work!

It almost seems as if the posters original idea would work:

[DefaultValue(true)]
public bool IsAdmin { get; set; }

I thought they just made the mistake of adding quotes... but alas no such intuitiveness. The other suggestions were just too much for me (granted I have the privileges needed to go into the table and make the changes... where not every developer will in every situation). In the end I just did it the old fashioned way. I set the default value in the SQL Server table... I mean really, enough already! NOTE: I further tested doing an add-migration and update-database and the changes stuck. enter image description here


It's simple! Just annotate with required.

[Required]
public bool MyField { get; set; }

the resultant migration will be:

migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);

If you want true, change the defaultValue to true in the migration before updating the database


I found that just using Auto-Property Initializer on entity property is enough to get the job done.

For example:

public class Thing {
    public bool IsBigThing{ get; set; } = false;
}

Hmm... I do DB first, and in that case, this is actually a lot easier. EF6 right? Just open your model, right click on the column you want to set a default for, choose properties, and you will see a "DefaultValue" field. Just fill that out and save. It will set up the code for you.

Your mileage may vary on code first though, I haven't worked with that.

The problem with a lot of other solutions, is that while they may work initially, as soon as you rebuild the model, it will throw out any custom code you inserted into the machine-generated file.

This method works by adding an extra property to the edmx file:

<EntityType Name="Thingy">
  <Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />

And by adding the necessary code to the constructor:

public Thingy()
{
  this.Iteration = 1;

After @SedatKapanoglu comment, I am adding all my approach that works, because he was right, just using the fluent API does not work.

1- Create custom code generator and override Generate for a ColumnModel.

   public class ExtendedMigrationCodeGenerator : CSharpMigrationCodeGenerator
{

    protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
    {

        if (column.Annotations.Keys.Contains("Default"))
        {
            var value = Convert.ChangeType(column.Annotations["Default"].NewValue, column.ClrDefaultValue.GetType());
            column.DefaultValue = value;
        }


        base.Generate(column, writer, emitName);
    }

}

2- Assign the new code generator:

public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext>
{
    public Configuration()
    {
        CodeGenerator = new ExtendedMigrationCodeGenerator();
        AutomaticMigrationsEnabled = false;
    }
}

3- Use fluent api to created the Annotation:

public static void Configure(DbModelBuilder builder){    
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);            
}

Examples related to entity-framework

Entity Framework Core: A second operation started on this context before a previous operation completed EF Core add-migration Build Failed Entity Framework Core add unique constraint code-first 'No database provider has been configured for this DbContext' on SignInManager.PasswordSignInAsync The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked Auto-increment on partial primary key with Entity Framework Core Working with SQL views in Entity Framework Core How can I make my string property nullable? Lazy Loading vs Eager Loading How to add/update child entities when updating a parent entity in EF

Examples related to ef-code-first

EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType There is already an object named in the database The entity type <type> is not part of the model for the current context Entity Framework 6 Code first Default value Unique Key constraints for multiple columns in Entity Framework Entity Framework (EF) Code First Cascade Delete for One-to-Zero-or-One relationship Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why? How to delete and recreate from scratch an existing EF Code First database Entity Framework: One Database, Multiple DbContexts. Is this a bad idea? Ignoring a class property in Entity Framework 4.1 Code First

Examples related to default-value

How to set a default value in react-select How to set default values in Go structs What is the default value for Guid? CURRENT_DATE/CURDATE() not working as default DATE value Entity Framework 6 Code first Default value Default values and initialization in Java Python argparse: default value or specified value Javascript Get Element by Id and set the value Why is the default value of the string type null instead of an empty string? SQL Column definition : default value and not null redundant?