Best way to override SaveChanges()
This code will be better with :
var added = this.ChangeTracker.Entries()
.Where(t => t.Entity is ITrack && t.State == EntityState.Added)
.Select(t => t.Entity)
.ToArray();
The same for modified :
var modified = this.ChangeTracker.Entries()
.Where(t => t.Entity is ITrack && t.State == EntityState.Modified)
.Select(t => t.Entity)
.ToArray();
And remove if conditions in foreach loop...
you can do the following
1- create an Interface in your application that all the classes that has the following properties will implement this interface: Id, CreatedDate,CreatedBy, ModifiedDate,ModifiedBy
public interface ITrack
{
int Id{get; set;}
int CreatedBy{get; set;}
DateTime CreatedDate{get; set;}
int? ModifiedBy{get; set;} // int? because at first add, there is no modification
DateTime? ModifiedBy {get; set;}
}
Best practices Define the
CreatedBy
andModifiedBy
asstring
which will be good for performance and maintenance
2- Add a class TrackableEntry
which implements the interface ITrack
public abstract class TrackableEntry : ITrack
{
public int Id{get; set;}
public int CreatedBy{get; set;}
public DateTime CreatedDate{get; set;}
public int? ModifiedBy{get; set;}
public DateTime? ModifiedBy {get; set;}
}
3- remove the properties mentioned in the interface from all of your classes and let these classes to implement directly from TrackableEntry
public class A: TrackableEntry
{
//public int Id{get; set;}
//public int CreatedBy{get; set;}
//public DateTime CreatedDate{get; set;}
//public int? ModifiedBy{get; set;}
//public DateTime? ModifiedBy {get; set;}
}
4- In your DbContext
file override your SaveChanges
and add property UserId
or UserName
if you followed the *Best practices*
part
public int UserId{get; set;}
public override int SaveChanges()
{
this.ChangeTracker.DetectChanges();
var added = this.ChangeTracker.Entries()
.Where(t => t.State == EntityState.Added)
.Select(t => t.Entity)
.ToArray();
foreach (var entity in added)
{
if (entity is ITrack)
{
var track = entity as ITrack;
track.CreatedDate = DateTime.Now;
track.CreatedBy = UserId;
}
}
var modified = this.ChangeTracker.Entries()
.Where(t => t.State == EntityState.Modified)
.Select(t => t.Entity)
.ToArray();
foreach (var entity in modified)
{
if (entity is ITrack)
{
var track = entity as ITrack;
track.ModifiedDate = DateTime.Now;
track.ModifiedBy = UserId;
}
}
return base.SaveChanges();
}
finally in your forms when you want to call SaveChanges
method, ensure you set the UserId
or UserName
value
var entities=new Entities(); // assuming that your DbContext file called Entities
// code for adding or deletion or modification here
entities.As.Add(new A(){...});
// ....
entities.UserId=MyUser;
entities.SaveChanges();
hope this will help you
To 'override' SaveChanges
without needing to create all that extra code, I wrapped it in its own extension method. i.e.
public static int SaveChangesWrapped(this MyDbContext db)
{
// do other things
return db.SaveChanges();
}
or async...
public static Task<int> SaveChangesAsyncWrapped(this MyDbContext db)
{
// do other things
return await db.SaveChangesAsync();
}
You can tweak it however you need, i.e. add other parameters, make it generic, etc. I may be missing something but this was enough for me to 'override' SaveChanges
and cut down a whole lot of repeated code.
Then anywhere in your code when you want to save, it's just:
db.SaveChangesWrapped();
//or
await db.SaveChangedAsyncWrapped();