代码之家  ›  专栏  ›  技术社区  ›  Collin Barrett

在自定义dbset种子期间应用删除<t>

  •  1
  • Collin Barrett  · 技术社区  · 7 年前

    我正在尝试扩展我的自定义种子例程(我知道ef core 2.1支持本地播种,但我有一个 blocker 在转换中)应用删除。如果数据库中存在记录,但种子数据中已不存在该记录,我希望将其删除。而不是为每个 DbSet ,我正在尝试使用泛型实现(如果需要,还可能进行反射)。

    我的第一次尝试:

    private static void Delete<TEntity>(DbContext dbContext, IEnumerable<TEntity> seedRows) where TEntity : class, IBaseEntity
    {
        var toRemove = dbContext.Set<TEntity>().Except(seedRows);
        dbContext.RemoveRange(toRemove);
        dbContext.SaveChanges();
    }
    

    然而,由于 TEntity 包含种子数据中为空的一些属性(例如在添加时生成的时间戳),我无法比较 Except() 调用(使用默认的相等比较器)。我只关心比较主键。

    我正在进行的解决这个问题的工作如下。 柔韧性 可以有一个简单的 Id 列,或者它可以是一个多对多的映射,复杂的主键为2。 <EntityName>Id S. IBaseEntity 目前没有 身份证件 /主键信息,因为它既由基本实体实现,也由多对多/连接实体实现。

    private static void Delete<TEntity>(DbContext dbContext, IEnumerable<TEntity> seedRows) where TEntity : class, IBaseEntity
    {
        var idProperties = typeof(TEntity).GetProperties().Where(p => p.Name.Contains("Id"));
        var toRemove = dbContext.Set<TEntity>().Select(s => idProperties).Except(seedRows.Select(s => idProperties));
        dbContext.RemoveRange(toRemove);
        dbContext.SaveChanges();
    }
    

    full source/context

    两个例子 .Select(s => idProperties) 但是,显然不起作用。有没有办法选择 身份证件 属性(或者,也可以是主键) DbSet<T> 用于 例外() 比较器?我也愿意接受一个完全不同的方法,因为我觉得自己像在杂草丛中。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Ivan Stoev    7 年前

    EF核心元数据提供所有必要的信息。

    您可以使用 Expression 类以动态生成这样的条件(伪代码):

    (seedRows1.Key1 == e.Key1 && seedRows1.Key2 == e.Key2 ... && seeedRows1.KeyM == e.KeyM)
    ||
    (seedRows2.Key1 == e.Key1 && seedRows2.Key2 == e.Key2 ... && seeedRows2.KeyM == e.KeyM)
    ...
    ||
    (seedRowsN.Key1 == e.Key1 && seedRowsN.Key2 == e.Key2 ... && seeedRowsN.KeyM == e.KeyM);
    

    从数据库返回匹配项。为了得到不匹配的项,可以简单地反转条件,并将其用作删除的谓词。请注意,对于单个pk,这将转换为 NOT IN (...) SQL标准。

    付诸行动:

    private static void Delete<TEntity>(DbContext dbContext, IEnumerable<TEntity> seedRows)
        where TEntity : class//, IBaseEntity
    {
        var entityType = dbContext.Model.FindEntityType(typeof(TEntity));
        var entityPK = entityType.FindPrimaryKey();
        var dbEntity = Expression.Parameter(entityType.ClrType, "e");
        Expression matchAny = null;
        foreach (var entity in seedRows)
        {
            var match = entityPK.Properties
                .Select(p => Expression.Equal(
                    Expression.Property(dbEntity, p.PropertyInfo),
                    Expression.Property(Expression.Constant(entity), p.PropertyInfo)))
                .Aggregate(Expression.AndAlso);
            matchAny = matchAny != null ? Expression.OrElse(matchAny, match) : match;
        }
        var dbQuery = dbContext.Set<TEntity>().AsQueryable();
        if (matchAny != null)
        {
            var predicate = Expression.Lambda<Func<TEntity, bool>>(Expression.Not(matchAny), dbEntity);
            dbQuery = dbQuery.Where(predicate);
        }
        var dbEntities = dbQuery.ToList();
        if (dbEntities.Count == 0) return;
        dbContext.RemoveRange(dbEntities);
        dbContext.SaveChanges();
    }