title: EF Core - set field values automatically
body: <p>I'm developing a web app using <strong>ASP.NET Core</strong> + <strong>Entity Framework Core</strong>.</p>
  
  <p>I'd like to store more info regarding <em>creation</em>, <em>modification</em> &amp; <em>deletion</em>.</p>
  
  <p>My EF entities implement interfaces which bring the following fields:</p>
  
  <ul>
  <li><code>DateTime CreationTime { get; set; }</code></li>
  <li><code>long? CreatorUserId { get; set; }</code></li>
  <li><code>DateTime? ModificationTime { get; set; }</code></li>
  <li><code>long? ModifierUserId { get; set; }</code></li>
  <li><code>DateTime? DeletionTime { get; set; }</code></li>
  <li><code>public long? DeleterUserId { get; set; }</code></li>
  <li><code>bool IsDeleted { get; set; }</code></li>
  <li><code>int TenantId { get; set; }</code></li>
  </ul>
  
  <p>I've been trying to make my app set all of the fields <strong>automatically</strong>.</p>
  
  <h2>Right now I am only able to handle the <code>DateTime</code> fields:</h2>
  
  <p><code>AppDbContext.cs</code></p>
  
  <pre><code>public override async Task&lt;int&gt; SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
  {
      ChangeTracker.DetectChanges();
      ChangeTracker.ProcessModifiedTime();
      ChangeTracker.ProcessSoftDelete();
      ChangeTracker.ProcessCreationTime();
  
      return (await base.SaveChangesAsync(true, cancellationToken));
  }
  </code></pre>
  
  <p><code>ChangeTrackerExtensions.cs</code></p>
  
  <pre><code>public static class ChangeTrackerExtensions
  {
      public static void ProcessCreationTime(this ChangeTracker changeTracker)
      {
          foreach (var item in changeTracker.Entries&lt;ICreationTime&gt;().Where(e =&gt; e.State == EntityState.Added))
          {
              item.CurrentValues[AppConsts.CreationTime] = DateTime.Now;
          }
      }
  
      public static void ProcessModifiedTime(this ChangeTracker changeTracker)
      {
          foreach (var item in changeTracker.Entries&lt;IModificationTime&gt;().Where(e =&gt; e.State == EntityState.Modified))
          {
              item.CurrentValues[AppConsts.ModificationTime] = DateTime.Now;
          }
      }
  
      public static void ProcessSoftDelete(this ChangeTracker changeTracker)
      {
          foreach (var item in changeTracker.Entries&lt;ISoftDelete&gt;().Where(e =&gt; e.State == EntityState.Deleted))
          {
              item.State = EntityState.Modified;
              item.CurrentValues[AppConsts.IsDeleted] = true;
              item.CurrentValues[AppConsts.DeletionTime] = DateTime.Now;
          }
      }
  }
  </code></pre>
  
  <hr>
  
  <p>At a <em>Service Layer</em> or <em>Controller</em> level it is possible to assign the required value each time (<code>CreatorUserId</code>, <code>MofidierUserId</code>, <code>DeleterUserId</code>) but this becomes a routine task, <strong>very tedious</strong>.</p>
  
  <p>I've seen the <a href="https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.EntityFrameworkCore/EntityFrameworkCore/AbpDbContext.cs#L224" rel="nofollow noreferrer">AspNetBoilerplate implementation</a>, but what worries me about it is that the developers make their DbContext dependent on Session and other stuff.</p>
  
  <pre><code>public abstract class AbpDbContext : DbContext, ITransientDependency, IShouldInitialize
  { 
      public IAbpSession AbpSession { get; set; }
      public IEntityChangeEventHelper EntityChangeEventHelper { get; set; }
      public ILogger Logger { get; set; }
      public IEventBus EventBus { get; set; }
      public IGuidGenerator GuidGenerator { get; set; }
      public ICurrentUnitOfWorkProvider CurrentUnitOfWorkProvider { get; set; }
      public IMultiTenancyConfig MultiTenancyConfig { get; set; }
      ...
  </code></pre>
  
  <p>IMHO, this is a typical <strong>violation of Single Responsibility Principle</strong>.</p>
  
  <p>I tried looking into <a href="https://docs.microsoft.com/en-us/ef/ef6/fundamentals/logging-and-interception" rel="nofollow noreferrer">interceptors</a>, but they seem to be available only in ordinary (non-core) edition of <strong>Entity Framework</strong> - still haven't managed to get my head around how to implement what I mentioned above.</p>
  
  <p>Really, I'm completely lost as to how to handle it with Entity Framework Core. Can anyone think of any Service Layer level solution for that? Or maybe there's a better way?</p>