78

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)?

1
  • 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). 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. Commented Mar 13, 2018 at 22:14

5 Answers 5

144

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()"));
Sign up to request clarification or add additional context in comments.

7 Comments

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
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. :(
Quoting @Efrain, with EF Core 5 and MySQL I got empty fields. The default is not applied.
How to add default value of other column, eg: I want the new property default vaue to be report.OldProperty ?
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.
|
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
        )
    );
}

2 Comments

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.
Is it possible to have the default be a function of other fields?
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"));

Comments

-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();
    }
    

Comments

-6

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;
}

1 Comment

What's wrong is that it's not actually setting a default value in the database.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.