SavingChanges 时如何在 DbContext 中获取正确的 DbSet<Entity>?

How to get proper DbSet<Entity> in DbContext when SavingChanges?

我有一个类似

的 DbContext
public class MyContext : DbContext
{
   public DbSet<Entity1> Entities1 { get; set; }
   public DbSet<Entity2> Entities2 { get; set; }
   . . .
}

其中 Entity1Entity2 继承基础 class

public abstract class BaseEntity
{
   [DatabaseGenerated(DatabaseGeneratedOption.None)]
   public int Id { get; set; }
   . . .
}

出于某种原因,我需要删除数据库中的自动递增并在上下文中进行自定义自动递增以避免数据库影响。所以我决定估计 Id 列中的当前最大值并增加它。
我创建了一个简单的方法

private int GetMaxId(IQueryable<BaseEntity> set)
{
   if (set.Count() == 0) return 0;
   else return set.Max(x => x.Id);
}

所以在上下文构造函数中我做了以下操作:

public MyContext() : base("MyConnection")
{
   . . .

   var objectContext = ((IObjectContextAdapter)this).ObjectContext;
   objectContext.SavingChanges += (sender, args) =>
   {
      foreach (var entry in ChangeTracker.Entries())
      {
         var entity = entry.Entity;
         var state = entry.State;
         if (entity is BaseEntity)
         {
            switch (entry.State)
            {
               case EntityState.Added:
                  var set = Set<entity.GetType()>();
                  (entity as BaseEntity).Id = GetMaxId(set) + 1;
               . . .
            }
         }
      }
      ChangeTracker.DetectChanges();
   };

   . . .
}

但问题是我不能像 Set<entity.GetType()>()Set<typeof(entity)>() 一样构造 DbSet - 它说最后一个 ) 是无效的表达式。虽然它不依赖于 amount\order 的括号。
Set(entity.GetType()) 也不适合我,因为它 returns 是一个未类型化的 DbSet。

请告诉我如何解决这个问题或我做错了什么。

您不能在运行时将类型确定为泛型类型参数。 对于您的情况,此解决方法应该有效:

public MyContext() : base("MyConnection")
{
  var objectContext = ((IObjectContextAdapter) this).ObjectContext;
  objectContext.SavingChanges += (sender, args) =>
  {
    foreach (var entry in ChangeTracker.Entries())
    {
      var entity = entry.Entity;
      var state = entry.State;
      if (entity is BaseEntity)
      {
        ProcessEntity((BaseEntity)entity, state);
      }
    }
    ChangeTracker.DetectChanges();
  };
}

private void ProcessEntity<T>(T entity, EntityState state) where T : BaseEntity
{
  switch (state)
  {
    case EntityState.Added:
      var set = Set<T>();
      (entity as BaseEntity).Id = GetMaxId(set) + 1;
      break;
  }
}

您可以使用以下代码按实体类型获取 DbSet

var set = Set(entity.GetType());

经过长时间的 DbSet 转换我终于找到了解决方案。问题是我们不需要转换 DbSet,我们必须转换它的元素。

很明显。

因此 GetMaxId 的最终版本(在我们检查 entityBaseEntity 之前 GetMaxId 调用的情况下)是

    private int GetMaxId(DbSet set)
    {
        int max = 0;
        foreach (var item in set)
        {
            int id = (item as BaseEntity).Id;
            if (id > max) max = id;
        }
        return max;
    }

对应的情况是

case EntityState.Added:
   (entity as BaseEntity).Id = GetMaxId(Set(entity.GetType())) + 1;
   . . .

就像@alisabzevari 说的那样。