75

I am using EF6 for storing instances of the report class in my database. The database already contains data. Say I wanted to add a property to report,

public class report {
    // ... some previous properties

    // ... new property:
    public string newProperty{ get; set; }
}

Now if I go to the package-manager console and execute

add-migration Report-added-newProperty
update-database

I will get a file in the '/Migrations' folder adding a newProperty column to the table. This works fine. However, on the older entries in the database, the value for the newProperty is now an empty string. But I want it to be, e.g., "old".

So my question is: How do I set default values for new properties (of any type) in the migration script (or elsewhere)?

Noctis
  • 11,507
  • 3
  • 43
  • 82
EluciusFTW
  • 2,565
  • 6
  • 42
  • 59
  • 1
    The behavior here is not due to entity framework but TSQL. When you add a new nullable column in TSQL then one must use `WITH VALUES` to specify the value of existing records (see this [question](https://stackoverflow.com/questions/92082/add-a-column-with-a-default-value-to-an-existing-table-in-sql-server)). The workaround given in answers here is to make the column non-nullable. Another alternative is to define a custom DefaultValue attribute such as [this](https://stackoverflow.com/a/34894274/5301903). – Hans Vonn Mar 13 '18 at 22:14

5 Answers5

135

If you see the generated migration code you will see AddColumn

AddColumn("dbo.report", "newProperty", c => c.String(nullable: false));

You can add defaultValue

AddColumn("dbo.report", "newProperty", 
           c => c.String(nullable: false, defaultValue: "old"));

Or add defaultValueSql

AddColumn("dbo.report", "newProperty",
           c => c.String(nullable: false, defaultValueSql: "GETDATE()"));
Christoph Fink
  • 22,727
  • 9
  • 68
  • 113
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
  • 26
    Would be nice if it properly pulled in the [DefaultValue(xyz)] attribute as defined in the code first model. Instead of having to remember which columns need what each time you Add-Migration; having to post-edit the generated file, followed by the normal running of the Update-Database against that changed file. I wonder if it's possible to override that unintelligent behavior.... I can't believe no one has improved on this. Surely I'm not the only one frustrated by this with the default AspNet Identity model... LockoutEnabled, EmailConfirmed, AccessFailedCount. all hardcoded, all problems – Barry Apr 02 '17 at 08:42
  • 5
    This does not seem to work with MySQL-EF. 'defaultValue' doesn't set the value, and 'defaultValueSql' creates an exception ("blob text geometry or json column can't have a default value") ... the only workaround left is to use raw SQL. :( – Efrain Nov 06 '17 at 12:56
  • For those that needed default value for an enum just like me: AddColumn("dbo.report", "newEnumProperty", c => c.Int(nullable: false, defaultValue: 0)); //use integer to set default enum value – EeKay Jun 13 '18 at 10:07
  • 1
    Quoting @Efrain, with EF Core 5 and MySQL I got empty fields. The default is not applied. – StefanoV Dec 16 '20 at 09:50
  • 2
    How to add default value of other column, eg: I want the new property default vaue to be report.OldProperty ? – user1735921 Apr 10 '21 at 19:10
  • Also this applies for migration **only**. I was worried it would set default value for future insertion operations and after testing, it is not the case. If you do want default value for the field for new insertions, set it using models. – Luke Vo Jan 30 '23 at 08:35
22

Hope it helps someone. Putting everything together from previous answers (example using a boolean property):

1) Add a new property to the entity.

/// <summary>
/// Determines if user is enabled or not. Default value is true
/// </summary>
public bool IsEnabled { get; set; }

2) Run the command below to add the new change in the migrations.

add-migration addIsEnabledColumn

3) A migration file is created from the command above, open that file.

enter image description here

4) Set the default value.

public override void Up()
{
    AddColumn(
        "dbo.AspNetUsers", 
        "IsEnabled", 
        c => c.Boolean(
            nullable: false, 
            defaultValue: true
        )
    );
}
John Smith
  • 7,243
  • 6
  • 49
  • 61
Victor LG
  • 606
  • 6
  • 7
  • 4
    5) Run Update-Database after step 4 to update the actual database too with the changes. Adding this point just for the sake of newbies. – vinmm Jun 11 '20 at 07:20
  • Is it possible to have the default be a function of other fields? – RJFalconer Sep 03 '21 at 20:28
7

You have to change the line in your migration script which adds the the property/column like this:

AddColumn("dbo.reports", "newProperty", c => c.String(nullable: false, defaultValue: "test"));
ngu
  • 874
  • 1
  • 9
  • 23
-2

I have resolved this problem by overriding the SaveChanges method. See below for my solution.

  1. Solution Explain

    i) Override the SaveChanges method in the DbContext class.

    public override int SaveChanges()
    {
        return base.SaveChanges();
    }
    

    ii) Write logic to set default values

    public override int SaveChanges()
    {
        //set default value for your property
        foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("YOUR_PROPERTY") != null))
        {
            if (entry.State == EntityState.Added)
            {
                if (entry.Property("YOUR_PROPERTY").CurrentValue == null)
                    entry.Property("YOUR_PROPERTY").CurrentValue = YOUR_DEFAULT_VALUE;
            }
        }
    
        return base.SaveChanges();
    }
    
  2. Example

    public override int SaveChanges()
    {
        //set default value for RegistedDate property
        foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("RegistedDate") != null))
        {
            if (entry.State == EntityState.Added)
            {
                if ((DateTime)entry.Property("RegistedDate").CurrentValue == DateTime.MinValue)
                    entry.Property("RegistedDate").CurrentValue = DateTime.Now;
            }
        }
    
        //set default value for IsActive property
        foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("IsActive") != null))
        {
            if (entry.State == EntityState.Added)
            {
                if(entry.Property("IsActive").CurrentValue == null)
                    entry.Property("IsActive").CurrentValue = false;
            }
        }
    
        return base.SaveChanges();
    }
    
shalitha senanayaka
  • 1,905
  • 20
  • 37
-7

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;
}
Velyo
  • 262
  • 1
  • 8