Overriding SaveChanges and setting ModifiedDate, but how do I set ModifiedBy?
You can use the HttpContext.Current.User.Identity.Name
to get the name of the current user.
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditable>();
if (changeSet != null)
{
foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
{
entry.Entity.ModifiedDate = DateProvider.GetCurrentDate();
entry.Entity.ModifiedBy = HttpContext.Current.User.Identity.Name;
}
}
return base.SaveChanges();
}
Better way to do this would be to use constructor injection to pass the current user to the context
public class MyContext : DbContext
{
public MyContext(string userName)
{
UserName = userName;
}
public string UserName
{
get; private set;
}
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditable>();
if (changeSet != null)
{
foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
{
entry.Entity.ModifiedDate = DateProvider.GetCurrentDate();
entry.Entity.ModifiedBy = UserName;
}
}
return base.SaveChanges();
}
}
Set Last Updated on each SaveChanges in Entity
Here is how you can do it by overriding SaveChanges
method:
public override int SaveChanges()
{
IEnumerable<DbEntityEntry<BaseEntity>> entries = ChangeTracker.Entries<BaseEntity>()
.Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);
foreach (DbEntityEntry<BaseEntity> entry in entries)
{
entry.Entity.LastUpdated = DateTime.Now;
}
return base.SaveChanges();
}
Best way to override SaveChanges()
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
How do I add a new record to objectStateEntryList in SaveChanges override
EF by default will use both - it uses original values to check for a concurrency issue (i.e. if the record has changed since you loaded the data from the DB) then uses the entity's current/modified values to update the DB record.
It is not possible to have EF "detect and handle these entities automatically". You will need to create a new instance of the entity object, copy the values from the existing entity object, set the appropriate effective and expired dates on both objects, add the new entity object to the DbContext, then save changes. The best place to do this is by overriding the SaveChanges() method of your DbContext. To keep it as clean and manageable as possible, I suggest using the repository pattern.
How to correctly override the SaveChanges function in EF 4.1
You can override in your context class,
public partial class YourDbContext: DbContext
{
public YourDbContext()
{
}
public override int SaveChanges()
{
// do your additional stuff here.. (Ex:- save current user)
return base.SaveChanges();
}
}
And the other option is you can set default values in the constructor of your entity,
Public class YourEntity{
public YourEntity(){
CreatedDate=DateTime.Now;
}
Public DateTime CreatedDate{get;set;}
}
Entity Framework 7 SaveChanges
ChangeTracker.Entries()
allows you to get all of the entity changes. You could override SaveChanges
in your DbContext and set the modified properties using something like the following code.
public override int SaveChanges()
{
SetModifiedInformation();
return base.SaveChanges();
}
public override async Task<int> SaveChangesAsync( CancellationToken cancellationToken = new CancellationToken() )
{
SetModifiedInformation();
return await base.SaveChangesAsync( cancellationToken );
}
private void SetModifiedInformation()
{
foreach (var entityEntry in ChangeTracker.Entries())
{
var entity = entityEntry.Entity as ChangeTracking;
if (entity != null)
{
entity.ModifiedBy = "Get User Here";
entity.ModifiedTime = DateTime.Now;
}
}
}
Related Topics
Run Code Once Before and After All Tests in Xunit.Net
Itextsharp - Sending In-Memory PDF in an Email Attachment
How to Tell When Httpclient Has Timed Out
Programmatically Add an Application to Windows Firewall
Create an Application Setup in Visual Studio 2013
Embed Unity3D App Inside Wpf Application
Getting Absolute Urls Using ASP.NET Core
C#:Is Variance (Covariance/Contravariance) Another Word for Polymorphism
How to Install a Certificate into the Local MAChine Store Programmatically Using C#
How to Catch SQLserver Timeout Exceptions
Can Bindings Create Memory Leaks in Wpf
Variables Within App.Config/Web.Config
Convert File Path to a File Uri
How to Remove Accents on a String
Conditional Compilation Depending on the Framework Version in C#