保存更改时,如何在 DbContext 中获取正确的 DbSet

本文关键字:DbSet Entity 获取 DbContext 保存更改 | 更新日期: 2023-09-27 18:33:06

我有一个像这样的 DbContext

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

其中Entity1Entity2继承基类

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);
}

所以在上下文构造函数中,我做了 folowing:

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()>()那样构造 DbSet,就像Set<typeof(entity)>()一样 - 它说最后一个)是无效表达式。虽然它不依赖于括号的数量''顺序。
Set(entity.GetType())也不适合我,因为它返回一个非类型化的 DbSet。

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

保存更改时,如何在 DbContext 中获取正确的 DbSet<Entity>

您可以使用

以下代码按实体类型获取DbSet

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

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

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而苦苦挣扎后,我终于找到了解决方案。问题是我们不需要铸造DbSet,我们必须铸造它的元素。

这显然。

因此,GetMaxId的最终版本(前提是我们在GetMaxId调用之前检查entity BaseEntity)是

    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说的那样。