Reputation:
We have worked on a project for 1 month and there are 6 entities without any relationship with other entities. They are all simple entities.
We have created 6 different classes for operations on each entity. SaveOrUpdateEntity()
methods of classes are almost same as you think. It is something like that:
public static ErrorType SaveOrUpdateEntity(Entity entity, int userID)
{
try
{
using (DataEntities ctx = new DataEntities())
{
if (entity != null)
{
if (entity.entityID == 0)
{
entity.CreateDate = DateTime.Now;
entity.CreatedBy = userID;
ctx.Entry(entity).State = EntityState.Added;
}
else
{
entity.ModifyDate = DateTime.Now;
entity.ModifiedBy = userID;
ctx.Entry(entity).State = EntityState.Modified;
}
}
ctx.SaveChanges();
}
return ErrorType.NoError;
}
catch (Exception ex)
{
return ErrorType.SaveError;
}
}
It would be very helpful, if SaveOrUpdateEntity()
method is shorter and more generic by overriding SaveChanges()
method. According to other questions, articles, and posts about overriding SaveChanges()
method, implementing interface that stores state of entities is a good solution but I am also wondering other solutions.
Because I am newbie, all answers would be very appreciated.
Thank you.
Upvotes: 17
Views: 24697
Reputation: 55
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...
Upvotes: 6
Reputation: 1012
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();
Upvotes: 0
Reputation: 6784
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
Upvotes: 34