Override SaveChanges in Entity Framework 5

6k views Asked by At

Using C#, I've generated my DB model using "Generate from Database". The POCO classes and context are generated with T4 templates. everything is working fine and the app is able to edit, insert etc. except I cannot override the SaveChanges method in my entities class. I need to do this to add buisiness logic. Here is the context class:

//------------------------------------------------------------------------------
// <auto-generated>
//    This code was generated from a template.
//
//    Manual changes to this file may cause unexpected behavior in your application.
//    Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace WebApplication1
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

   public partial class IInvoiceEntities2 : DbContext
   {
        public IInvoiceEntities2 ()
            : base("name=IInvoiceEntities2 ")
        {
        }        


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }






    public DbSet<Company> Companies { get; set; }
    public DbSet<CompanyDetail> CompanyDetails { get; set; }
    public DbSet<CompanyVersion> CompanyVersions { get; set; }
    public DbSet<CustomerDetail> CustomerDetails { get; set; }
    }
}

Any ideas why my SaveChanges method isn't being hit when I set a breakpoint in it and edit an entity?

Update:

I now override the ValidateEntity method in my context class as well as SaveChanges, but when I edit an entity and set a breakpoint in SaveChanges or ValidateEntity, neither methods are being called (see code above)

Update 2:

I've now created a partial class in App_Code folder for the SaveChanges and ValidateEntity, but these methods are still not being executed :

namespace WebApplication1
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

public partial class IInvoiceEntities2 : DbContext
{
    public IInvoiceEntities2 ()
        : base("name=IInvoiceEntities2 ")
    {
    }


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




protected override DbEntityValidationResult ValidateEntity(
System.Data.Entity.Infrastructure.DbEntityEntry entityEntry,
IDictionary<object, object> items)
{
  // do stuff

    if (result.ValidationErrors.Count > 0)
    {
        return result;
    }
    else
    {
        return base.ValidateEntity(entityEntry, items);
    }
}





}

}

3

There are 3 answers

0
DeadlyDan On BEST ANSWER

I've come up with a solid workaround to this issue since I wasn't able to override SaveChanges(). Instead I implement the OnUpdating event of the EntityDataSource :

<asp:EntityDataSource ID="DetailsDataSource" runat="server" EnableUpdate="true"     
OnUpdating="DetailsDataSource_Updating" />

Then I have this method in my code behind which allows me to do server side validation:

protected void DetailsDataSource_Updating(object sender, EntityDataSourceChangingEventArgs e)
    {
        Country c = (Country) e.Entity;
        if (c.CountryName != "North pole")
            e.Cancel = true;
    }

I wish I could override save changes but this will have to do for now. Thanks everyone for your help.

4
Wizzard On

you can use this partial class style if you want to override saving changes, it should be noted if the methods here are not called it's usually an indicator that partial class is not matching the actual class, check namespace etc.

public partial class MyEntities : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            SavingChanges();
            return base.SaveChanges();
        }
        catch (Exception exception)
        {
            //handle errors here
        }
    }

    private void SavingChanges()
    {
        using (var OC = new MyEntities())
        {
            var objects = this.ChangeTracker.Entries()
                .Where(p => p.State == EntityState.Added || 
                    p.State == EntityState.Deleted || 
                    p.State == EntityState.Modified);

            // handle auditing
            AuditingHelperUtility.ProcessAuditFields(
                objects.Where(p => p.State == EntityState.Added));
            AuditingHelperUtility.ProcessAuditFields(
                objects.Where(p => p.State == EntityState.Modified), InsertMode: false);

            // Inserted objects
            foreach (DbEntityEntry entry in objects
                .Where(p => p.State == EntityState.Added))
            {
                if (entry.Entity != null)
                {
                    // insert code 
                }
            }

            // Updated objects
            foreach (DbEntityEntry entry in objects
                .Where(p => p.State == EntityState.Modified))
            {
                if (entry.Entity != null)
                {
                    // update code 
                }
            }

            // Delete objects
            foreach (DbEntityEntry entry in objects
                .Where(p => p.State == EntityState.Deleted))
            {
                if (entry.Entity != null)
                {
                    // delete code 
                }
            }
        }
    }
}
0
LMK On

NOTE I've only tested this in EF6 not EF5

The way to do it that covers off all scenarios (including EntityDataSource) is to add a handler to the SavingChanges event of the underlying ObjectContext. This can be done from your DbContext constructor :

 var objCx = (this as IObjectContextAdapter).ObjectContext;
 objCx.SavingChanges += (s, e) => { .... }