10

I started by creating some models like this:

public abstract class EditableBase
{
    public DateTime CreatedOn { get; set; }
    public DateTime ModifiedOn { get; set; }

    public int CreatedBy { get; set; }
    public int ModifiedBy { get; set; }
}

public class Project : EditableBase
{
    public int ProjectId { get; set; }
    public string ProjectName { get; set; }
}

And I use this line when the app starts:

Database.SetInitializer<ModelContext>(
            new DropCreateDatabaseIfModelChanges<ModelContext>());

A table called Projects is created with all the properties mentioned above as columns... this is exactly what I wanted.

However, now I need populate some default values when I issue a SaveChanges() on DbContext. When I save I need to update the ModifiedOn and ModifiedBy properties with the appropriate values.

Normally I would at least do the DateTime values on the database side (either a trigger or a stored procedure) however this is obviously not an option here since the database will be dropped anytime a class changes. And since I did code first I do not have a model designer that I can tweak the properties on.

What I would like to do is add a method in the EditableBase class that gets called when the SaveChanges() is executed, thus keeping all the logic involved in one place. Is it possible to do this? What is the best way to achieve my goal?

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
Sailing Judo
  • 11,083
  • 20
  • 66
  • 97
  • Nice naming convention! I couldn't figure out a way to get the data type (Date) out of the names of the date fields. – Josh Kodroff Jun 13 '11 at 19:35

3 Answers3

9

Override SaveChanges in your derived DbContext:

public override int SaveChanges()
{
    foreach(var entry in ChangeTracker.Entries<EditableBase>())
    {
        var entity = entry.Entity;
        if (entry.State == EntityState.Added)
        {
            entity.CreatedOn = ...;
            entity.CreatedBy = ...;
        }
        else if (entry.State == EntityState.Modified)
        {
            entity.ModifiedOn = ...;
            entity.ModifiedBy = ...;
        }
    }

    return base.SaveChanges();
}

I'm only not sure if generic Entries will work directly with your base type becasue it is not actually mapped as base entity. There is also non generic version so you can rewrite it to more complex linq query or test each entry's entity type in loop.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • This appears to be the most correct answer. I'm not really thrilled with it because it seems like overkill, but I don't see any other option. – Sailing Judo May 19 '11 at 19:06
  • I used this for the DateCreated only. But when i do an Edit this value gets overwritten and set to null or empty string – Jepzen Sep 09 '14 at 12:01
  • What if used auto-properties, will it have the same effect?: `public DateTime ModifiedOn { get; set; } = Datetime.Now;` – mshwf Oct 27 '16 at 12:38
0

Well, you have complete control over the code for your entities. I'd imagine you would probably want to implement an IPropertyChanged like pattern to update your properties.

Tejs
  • 40,736
  • 10
  • 68
  • 86
  • Can you possibly expand on this answer? I know I have complete control over my entities, but I do not know that I have complete control over the SaveChanges() method in DbContext. Where is the hook I need? – Sailing Judo Mar 31 '11 at 14:53
  • I was merely pointing out that you could implement an IPropertyChanged on your entities (similar to WPF); aka, when a property changes, you update the ModifiedOn property yourself instead of inside SaveChanges. – Tejs Mar 31 '11 at 15:00
  • I see what you mean now. That seems like potentially a lot of work. For example, if I have a dozen models that all inherit from EditBase, and each of those has 20 or 30 properties, I have to add a lot of code for something I *know* will always be needed when the EditBase is inherited and the SaveChanges() is called. – Sailing Judo Mar 31 '11 at 15:10
0

Did consider the two options in this post where you do something on the setter (or constructor)?

The default attribute solution seems a good one.

Community
  • 1
  • 1
jenson-button-event
  • 18,101
  • 11
  • 89
  • 155
  • Well, this solution partially works and its ultimately what I chose to do. Its a little clunky though. It doesn't work when a saved valued loads and overwrites whatever the constructor put in. ModifiedBy is a good example of this. I really want to set this ONLY when I save. – Sailing Judo May 19 '11 at 19:04