This might be a simple question, however I'm new to Code First and Migrations so bear with me. I'll keep sample code to a minimum to show the problem:
I have a BaseAuditableEntity
which includes this (among other things, but let's simplify):
public abstract class BaseAuditableEntity : BaseEntity, IAuditableEntity
{
public DateTime CreatedOn { get; set; }
public DateTime LastModified { get; set; }
}
Now a (for example) User
POCO inherits from it:
public class User : BaseAuditableEntity
{
public string UserName { get; set; }
public string PasswordHash { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public bool Active { get; set; }
public DateTime? LastLogin { get; set; }
}
I have this on my context's SaveChanges
method, to fill in the CreatedOn
and LastModified
dates (simplified):
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditableEntity>();
if (changeSet != null)
{
foreach (var entry in changeSet.Where(p => p.State != EntityState.Unchanged))
{
var now = DateTime.UtcNow;
if (entry.State == EntityState.Added)
entry.Entity.CreatedOn = now;
entry.Entity.LastModified = now;
}
}
return base.SaveChanges();
}
And now I have a migration in place that seeds some users, like this:
protected override void Seed(MyContext context)
{
context.Users.AddOrUpdate(
p => p.UserName,
new User { Active = true,
FullName = "My user name",
UserName = "ThisUser",
PasswordHash = "",
Email = "my@email",
LastLogin = null,
}
// etc.
);
}
Now I have a problem on seeding with AddOrUpdate
after the migration. When the entity is new (it's being added), CreatedOn
gets filled correctly and everything works as expected. However when the entity is modified (it already exists on the database and UserName
matches), it tries to update it with the new entity I'm creating... this fails because CreatedOn
has an invalid DateTime
(in this case, DateTime.MinValue
).
Is there any way to use the AddOrUpdate
method so that it actually retrieves the matching entity from the database and just update the non-default fields? Or maybe some way to tell it which fields NOT to update? For this specific case, I'd like the CreatedOn
field to be unchanged, but a generic solution would be appreciated.
Maybe I should do my own AddOrUpdate
method which includes a predicate with the fields I want to change, instead of passing it a completely new entity?
This is EF 6.1
Update
I know I can easily solve this for the CreatedOn
date, this is what I'm currently doing for this specific case:
foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
{
var now = DateTime.UtcNow;
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedOn = now;
}
else
{
if (entry.Property(p => p.CreatedOn).CurrentValue == DateTime.MinValue)
{
var original = entry.Property(p => p.CreatedOn).OriginalValue;
entry.Property(p => p.CreatedOn).CurrentValue = original != SqlDateTime.MinValue ? original : now;
entry.Property(p => p.CreatedOn).IsModified = true;
}
}
entry.Entity.LastModified = now;
}
I am looking for a more generic solution though