select ef core 中的命名字段 select 使用泛型的语句

select named field in ef core select statement which uses generics

我有下面的方法可以将新记录插入我的数据库

public static async Task SaveDataToEntitySetAsync<TEntity>(DbContext context,List<TEntity> list) 
    where TEntity : class
{
    if(list.Any() == false)
        return;
    
     var dbSet = context.Set<TEntity>();
     var existingData = await dbSet.Select(x=>x.Id).ToListAsync();
     list.RemoveAll(x => existingData.Contains(x.Id));
     await dbSet.AddRangeAsync(list);
}

如果我不使用泛型,上面的逻辑就是我正在尝试做的事情

如何将其转换为适用于泛型的语法?此语法在通用上下文中不起作用,因为 .Id 无效

我正在使用 EF Core,因此当一条记录添加到 table 时,EF Core 会自动将记录添加到关联的外键 tables

这种方法的问题是我在上下文中为每个 table 调用了这种方法。

假设添加了一位英国客户。这很好,添加了客户,并添加了英国国家(假设它还不存在)

我还有一个保存到数据库中的所有国家的摘录。显然这现在会中断,因为 UK 已经被保存

因此我试图从我的国家/地区列表中删除数据库中已有的任何项目

我的所有实体都来自 BaseEntity(这是定义 Id 的地方),但我不确定如何利用该事实

保罗

由于您的实体已经继承自具有 Id 属性 的相同基础 class,您可以将泛型类型限制为:

where TEntity : BaseEntity

您可以传递 Expression<Func<TEntity, TKey>> keyExtractor lambda 表达式,例如 x => x.Id:

public static async Task SaveDataToEntitySetAsync<TEntity, TKey>(DbContext context, List<TEntity> list, Expression<Func<TEntity, TKey>> keyExtractor)
    where TEntity : class
{
    if (list.Any() == false)
        return;

    var dbSet = context.Set<TEntity>();
    var existingData = await dbSet.Select(keyExtractor).ToListAsync();

    Func<TEntity, TKey> keyExtractorCompiled = keyExtractor.Compile();
    list.RemoveAll(x => existingData.Contains(keyExtractorCompiled(x)));

    await dbSet.AddRangeAsync(list);
}

然后:

await SaveDataToEntitySetAsync(..., x => x.Id);