5

Background: I’m beginning a project to convert a web application using Linq2Sql to use Entity Framework (v6) instead. I have a lot of experience with L2S, but I’m brand-new to EF. Since our application and its database already exist, we’re using the “Database First” approach. Also, the database is evolving, so we’re making changes in the schema and the model is updated from the revised database, which regenerates code for the EF model each time.

For many of our entities (database tables), we set default values in our code whenever an entity is constructed. In Linq2Sql it’s easy: define a partial class for the entity, and add a method to the class like this:

partial void OnCreated() { SomeProperty = SomeDefaultValue; }

Whenever Linq2Sql constructs a new entity object, it calls the OnCreated() method you define, and the default values are set as desired. It works great.

The Problem: In EF, I don’t see a way to do this in a Database First scenario.

  • If I modify the model code generated by EF, the model code is overwritten whenever we update the model after a database revision.

  • If I define a partial class for the entity in a separate file and define a constructor, the compiler complains that the constructor is already defined.

  • There doesn’t seem to be any support for something like L2S's OnCreated() method, either.

Any suggestions?

EDIT: Thanks everyone for the helpful comments, but I think I need to point out an important consideration: My goal is to use the database-first approach and stick with it, rather than switching to code-first. When the database schema changes over time I want the EF Designer (or POCO Generator or whatever tools) to update my EF entity classes to match. All without losing my additions to initialize class properties when the class is constructed in the application. This is easy in Linq2Sql, but I just don’t see a way to accomplish this in EF database-first. All suggestions are welcome!

4
  • You can modify the T4 template to add partial void OnCreated inside the constructor. Commented Jan 21, 2017 at 9:43
  • Aren't the T4 (tt) templates overwritten when you revise the database and then EF regenerates the EF model? Commented Jan 21, 2017 at 13:51
  • In fact the T4 (tt) templates are generating your entity model. Commented Jan 21, 2017 at 14:08
  • I ran a test by adding the OnCreated() method in the tt file and it worked as expected. Unfortunately, when I changed the table schema and updated the model from the database (using EF Designer), the tt file is overwritten and the OnCreated() method is lost. Commented Jan 21, 2017 at 16:48

5 Answers 5

5

1 . Open .edmx file

2 . Select the field that has the default value and go to the properties

3 . then select StoreGeneratedPattern

4 . then change the value to Computed

i think it's worked.

Sign up to request clarification or add additional context in comments.

1 Comment

Maybe write how this works. I think it is: "This solution fetches the default value from the database after save."
3

OP here – I’ve given credit for the answer to ErikEJ but I’d like to recap what I’ve learned on this topic to share with others. There are three goals:

  1. Use the database-first approach and stick with it, even as the database schema is changed over time. That is, have EF produce the code for each database table entity, based on a preexisting database, and update the code when the database is altered.

  2. Provide a mechanism to initialize entity object properties each time the object is constructed, such as Employee.Dependents = 1, for example. (I know simple defaults can be set by the database schema, but more complex initializations must be executed by code.)

  3. The custom initialization code must be preserved when the database schema is altered and EF regenerates the model code.

EF doesn’t provide a way to set properties each time an entity object is constructed in the database-first scenario. Editing the EF-generated code doesn’t work because it gets overwritten whenever EF regenerates the code after a change to the database schema. So far, four workarounds come to mind:

  1. One idea is to add a constructor with more than the default zero-parameter constructor for each entity class. For example, c = new Customer(x) rather than the default c = new Customer(). Application code would call the new constructor, which would inherit the default constructor and add additional code to initialize the class properties. This avoids duplicating the default constructor, something that isn’t permitted by C#. The new constructor is in a separate partial class file, so it will not be overwritten when EF generates updated models from the database.

    However, there is a risk that the application programmer may call the default constructor by accident, leading to subtle bugs.

  2. Another solution is to wrap the entity classes in another class, say, a Customer2 class wrapped around the Customer class. The new class would inherit the original class and add initialization code for any properties as needed.

    Since these new classes are separate from the original entity class code, they will not be overwritten by EF when it regenerates model code. It may be possible to hide the entity classes from the top-level application code, to avoid accidentally referring to the original classes by accident. If so, this should be a good technique, although I haven’t tested it yet.

  3. A third-party tool, EntityFramework Reverse POCO Generator, is a help. It generates POCO model code much as EF does, but it is not EF. It has an option to generate partial classes, and the entity classes include a InitializePartial() method much like Linq2Sql’s OnCreated(). I think this will work fine for regenerating code as the database is altered over time. My concern here is that this is a third-party product, and there’s always a risk that it can become obsolete or unsupported.

  4. Finally, you can alter the template that EF uses to generate code. The basic idea is to have the generated code add “partial void OnCreated()” to each class, and this lets us use the same convenient technique built into Linq2Sql. I assume newer versions of EF may overwrite the template changes, but it’s just one change in the template rather than changes to every entity class. This method is described here (How to efficiently set default entity values in Entity Framework 6, Database First) and the YouTube video is here (https://www.youtube.com/watch?v=i8J2ipImMuU).

Thanks to all who contributed! I hope this page is helpful to others, so you don’t have to burn as much time as I did looking for a solution.

Comments

1

Use the EF Reverse poco template- it will derive defaults from the database. You can override the InitializePartial method in your partial class to set defaults in code.

8 Comments

Not all defaults can come from the database. Some have to be computed at the time the entity is constructed. For an example, say, a new Customer entity may have different initial values depending on the Customer's country of residence.
The template also supports that!
Bearing in mind that I'm new to EF, this didn't quite work. From the EF Designer, I right-clicked to select "Add Code Generation Item" and ran the DbContext Generator. This generated the classes for each table entity (POCO files). I edited the file for my test entity to add the OnCreated method. All fine so far. Then I used the designer to "update model from database" and the edited file was overwritten. I verified that CodeGenerationStrategy was off. Grrr.
Wrong template! Go to Tools & Extensions and install, and read the docs on the Github site
Ok, thanks for that tip! It looks like this will work, after I turned on the option for partial classes. That said, I was hoping to make EF itself handle this itself, rather than another 3rd-party tool. This is a good 2nd-best solution.
|
0

Coming from the EF background, I generally do it in the code first migration manually. In the up function of the generated migration, you can do something like this

AddColumn("dbo.Person", "IsActive", c => c.Boolean(nullable: false, defaultValue: true));
AddColumn("dbo.Person", "Name", c => c.String(nullable: false, defaultValue: "Mirza"));

Or to add default SQL value, use

AddColumn("dbo.Person", "CreatedDate",
           c => c.String(nullable: false, defaultValueSql: "GETDATE()"));

However there's a downside of this approach in my opinion which is you have to keep a track of your (useless) migrations.

1 Comment

Thanks, but any suggestions for a database-first scenario?
0

Just found this post looking for an answer to the same issue. Here's a work around that works for me.

Create a partial class for the entity (DB Table) you want to specify default values for, eg:

namespace myApplication.MyModel
{
  public partial class myEntityName
  {
    public myEntityName(bool InitialiseOnConstruct) : this()
    {
      if (InitialiseOnConstruct) 
      {
        this.property1 = defaultValue1;
        this.property2 = defaultValue1;     
      }
    }
  }
}

Then in the code, to construct the entity:

thisEntity = new EntityName(true);

OK, it's an extra step, but it works. Hope that helps.

Comments

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.