Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using DateTime.UtcNow on model always creates a migration in Entity

I've got a few models that have a CreatedDate and/or UpdatedDate property, and in my seeding I'm setting those to DateTime.UtcNow.

new TestModel()
{
    Id = 1,
    Name = name,
    CreatedDateUtc = DateTime.UtcNow,
    CreatedBy = "Seed",
    UpdatedDateUtc = DateTime.UtcNow,
    UpdatedBy = "Seed",
    DeletedDateUtc = null,
    DeletedBy = null,
},

Now, even though the seed data is in the database, EF thinks that it needs to update them with a new date. Is that the expected behavior? Am I stuck specifying a date for those columns? Something like this:

DateTime(2020, 01, 01, 12, 00, 00, DateTimeKind.Utc)
like image 733
PiousVenom Avatar asked Mar 19 '20 13:03

PiousVenom


2 Answers

Every time when the seed method is running, it will overwrites all of the columns and every time the dates are different. If you want to prevent this overwrite enter data, then you need to check if it's not already exist in your db then run it. Or override the SaveChanges() method in the DbContext, if want to prevent update some fields.

Example:-

1.If you don't want to update enter data then--

protected override void Seed(ApplicationDbContext context)
{
    if (!context.TestModels.Any(u => u.Id== 1))
    {
          context.TestModels.AddOrUpdate(p => p.Id, new TestModel()
            {
                Id = 1,
                Name = "Test",
                CreatedDateUtc = DateTime.UtcNow,
                CreatedBy = "Seed",
                UpdatedDateUtc = DateTime.UtcNow,
                UpdatedBy = "Seed",
                DeletedDateUtc = null,
                DeletedBy = null,
            });
    }
 base.Seed(context);
}

2.If want to prevent update some fields(this process work for any entity from any where in the current DbContext)--

Attribute--

[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public sealed class IgnoreUpdateAttribute : Attribute
{
}

Model--

public class TestModel
{

    public int Id { get; set; }
    public string Name { get; set; }
    [IgnoreUpdate]//for ignoring update
    public DateTime CreatedDateUtc { get; set; }
    [IgnoreUpdate]//for ignoring update
    public string CreatedBy { get; set; }
    public DateTime UpdatedDateUtc { get; set; }
    public string UpdatedBy { get; set; }
    public DateTime? DeletedDateUtc { get; set; }
    public string DeletedBy { get; set; }
}

Seed--

    protected override void Seed(ApplicationDbContext context)
    {

        context.TestModels.AddOrUpdate(p => p.Id, new TestModel()
        {
            Id = 1,
            Name = "Test",
            CreatedDateUtc = DateTime.UtcNow,
            CreatedBy = "Seed",
            UpdatedDateUtc = DateTime.UtcNow,
            UpdatedBy = "Seed",
            DeletedDateUtc = null,
            DeletedBy = null,
        });

        base.Seed(context);
    }

DbContext--

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
        public DbSet<TestModel> TestModels { get; set; }
//---DB Set
        public override int SaveChanges()
        {
           var entities= ChangeTracker.Entries().Where(e => e.State == EntityState.Modified).ToList();
            foreach (var entry in entities)
            {
                var properties = typeof(TestModel).GetProperties()// get you model properties
                        .Where(property =>
                            property != null && Attribute.IsDefined(property, typeof(IgnoreUpdateAttribute)))//which has decorated as IgnoreUpdate
                        .Select(p => p.Name);
                foreach (var property in properties)
                {
                    entry.Property(property).IsModified = false;
                }
            }

            return base.SaveChanges();
        }
//--- Code
    }

(Tested)

like image 137
Ashiquzzaman Avatar answered Oct 18 '22 04:10

Ashiquzzaman


Seeding with HasData, EF will resolve the date to a new one ever time.

If I were you, I would use a predictable and reproducible seed by having a fixed date.

Or if you really need to use Now, you could try manual migration and checking beforehand if your table seed has already been run with some custom logic.

like image 2
Frédéric Colin Avatar answered Oct 18 '22 05:10

Frédéric Colin