【问题标题】:Adding CreatedDate to an entity using Entity Framework 5 Code First使用 Entity Framework 5 Code First 将 CreatedDate 添加到实体
【发布时间】:2013-01-01 08:52:21
【问题描述】:

我正在尝试向我的模型中的实体添加 CreatedDate 属性,并且正在使用 EF5 Code First。我希望这个日期一旦设置就不会更改,我希望它是 UTC 日期。我不想使用构造函数,因为我的模型中有许多实体想要从包含CreatedDate 属性的抽象类继承,并且我不能强制使用带有接口的构造函数。

我尝试了不同的数据注释,并尝试编写一个数据库初始化程序,该初始化程序将获取特定的实体类型,并为正确的table_namecolumn_name 编写一个带有getdate() 默认值的alter 约束,但是我无法正确编写该代码。

请不要让我参考AuditDbContext - Entity Framework Auditing ContextEntityFramework.Extended 工具,因为它们不能满足我的需要。

更新

我的 CreatedDateSaveChanges() 上为空,因为我将 ViewModel 传递给我的视图,其中正确地没有名为 CreatedDate 的审计属性。即使我将模型传递给我的视图,我也不会在视图中编辑或存储CreatedDate

我读到here,我可以添加[DatabaseGenerated(DatabaseGeneratedOption.Identity)],这将告诉EF 在插入和更新之后正确存储CreatedDate,但不允许我的应用程序更改它:但我只得到一个@ 987654335@ 添加此属性时出错。

我即将切换到 EF Model First,因为这个简单的数据库要求在 Code First 中实现是荒谬的。

【问题讨论】:

    标签: entity-framework ef-code-first entity-framework-5 code-first entity-framework-migrations


    【解决方案1】:

    对于 EF Core,您可以在此处找到 MS 推荐的解决方案: Default Values.

    在您的 DBContext 中使用 Fluent API:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Created)
            .HasDefaultValueSql("getdate()");
    }
    

    【讨论】:

      【解决方案2】:

      Stephans's Answer 类似,但与Reflection 类似,并且还会忽略所有用户(外部)更新的创建/更新时间。 Show Gist

        public override int SaveChanges()
              {
                  foreach (var entry in ChangeTracker.Entries().Where(x => x.Entity.GetType().GetProperty("CreatedTime") != null))
                  {
                      if (entry.State == EntityState.Added)
                      {
                          entry.Property("CreatedTime").CurrentValue = DateTime.Now;
                      }
                      else if (entry.State == EntityState.Modified)
                      {
                          // Ignore the CreatedTime updates on Modified entities. 
                          entry.Property("CreatedTime").IsModified = false;
                      }
      
                      // Always set UpdatedTime. Assuming all entities having CreatedTime property
                      // Also have UpdatedTime
                      // entry.Property("UpdatedTime").CurrentValue = DateTime.Now;
                      // I moved this part to another foreach loop
                  }
      
                  foreach (var entry in ChangeTracker.Entries().Where(
                      e => 
                          e.Entity.GetType().GetProperty("UpdatedTime") != null && 
                          e.State == EntityState.Modified || 
                          e.State == EntityState.Added))
                  {
                      entry.Property("UpdatedTime").CurrentValue = DateTime.Now;
                  }
      
                  return base.SaveChanges();
              }
      

      【讨论】:

        【解决方案3】:

        在您的上下文中覆盖 SaveChanges 方法:

        public override int SaveChanges()
        {
          DateTime saveTime = DateTime.UtcNow;
          foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == (EntityState) System.Data.EntityState.Added))
           {
             if (entry.Property("CreatedDate").CurrentValue == null)
               entry.Property("CreatedDate").CurrentValue = saveTime;
            }
            return base.SaveChanges();
        
        }
        

        因 cmets 而更新:只有新添加的实体才会设置其日期。

        【讨论】:

        • 很棒的建议,但其中一个问题是我没有将 CreatedDate 传递给我的视图。我将 ViewModel 传递给我的视图,然后使用 AutoMapper 将我的 ViewModel 中的字段映射到我的视图,因此 CreatedDate 在保存时将始终为空,我读到将 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 属性添加到我的 CreatedDate 将允许EF 正确加载数据库中的数据,插入或更新后重新加载数据 soentity 在应用程序中是最新的,同时不允许您更改值,但这只会导致错误
        • 不确定我是否理解正确。这里是晚上,我可能一直在喝酒——对不起。但是,如果 CreatedDate 对上下文不可用:那么数据库触发器怎么样。 (是的,当我提出 triggers 时,肯定是在喝酒)
        • 好吧,我通常会做一个触发器,但我正在使用 EF5 Code First。我可以通过 CodeFirst 添加触发器,但它违反了 CodeFirst 的主要原则,即将您的业务规则保存在一个地方。我不敢相信没有办法可以将实体属性设置为“只读”,因此,无论是否存在于上下文中,它都不会更新值,除非我明确这样做。跨度>
        • 请注意 EntityState 枚举在 System.Data.Entity 中(至少是 EF6)
        • 您应该存储DateTime.UtcNow 而不是本地日期。
        【解决方案4】:

        我是这样做的:

        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public DateTime CreatedDate{ get; set; }
        

        在我迁移的 Up() 方法中:

        AddColumn("Agents", "CreatedDate", n => n.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
        

        【讨论】:

        • 只有当你对课堂上的注释没问题时,我才使用 SaveChanges 方法答案。
        • @Rusty Divine:出于某种原因,总是将其设置为 01/01/1900 12:00:00 AM
        • 我在这里找到了更好的方法:andy.mehalick.com/2014/02/06/…
        • 如果生成值,需要set吗?或者你可以让属性只有一个get
        • 我是在我的 MVC 应用程序中完成的,现在我可以更新日期(我希望管理员能够在需要时更改日期)
        【解决方案5】:

        Code First 目前不提供提供列默认值的机制。

        您将需要手动修改或创建基类以自动更新 CreatedDate

        public abstract class MyBaseClass
        {
            public MyBaseClass()
            {
                CreatedDate = DateTime.Now;
            }
            public Datetime CreatedDate { get; set; }
        }
        

        【讨论】:

        • 但是当你更新一个实体时怎么样。在构造函数中将 CreatedDate 初始化为现在将覆盖更新时的原始 CreateDate。不是吗?这让我发疯了
        • @Adolfo 首先运行构造函数,然后设置本地字段的默认值,只有在此之后,EF 才会将 db-values 推送到内存中的实体对象中。所以不,对于现有实体,CreatedDate 的 db 值不会被 DateTime.Now 覆盖。
        【解决方案6】:

        好的,所以这里的主要问题是 CreatedDate 每次我调用 SaveChanges 时都会被更新,并且由于我没有将 CreatedDate 传递给我的视图,它被实体框架更新为 NULL 或 MinDate。

        解决方案很简单,知道我只需要在 EntityState.Added 时设置 CreatedDate,我只需在 SaveChanges 覆盖中执行任何工作之前设置我的 entity.CreatedDate.IsModified = false,这样我就忽略了来自更新和如果是 Add,则 CreatedDate 将在几行之后设置。

        【讨论】:

          【解决方案7】:
          Accounts account;
          account.Acct_JoinDate = DateTime.Now.ToUniversalTime();
          data.Accounts.Add(account);
          data.SaveChanges();
          

          为什么不在模型创建时给出时间戳?与此处的这些帐户类似。

          【讨论】:

          • 我希望审计功能自动化并且脱离我的控制器。我不希望其他开发人员每次添加时都必须记住输入 CreatedDate。
          猜你喜欢
          • 2014-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-29
          • 1970-01-01
          • 2013-10-17
          • 2014-05-08
          相关资源
          最近更新 更多