我有一个来自外部来源的实体列表。我需要将它与我已有的进行比较,并且只添加不存在的。下面是伪代码。
var newVersions = item.Versions
.Where(s => db.ExistingVersions
.Select(t=>t.versionID)
.DoesNotContains(s.versionID));
这显然不起作用,我不知道如何解决它。我不想使用 for 循环,因为我相信这意味着我将有数百次数据库命中只是为了检查每个项目的版本。我正在加载多个项目,每个项目有多达 100 个版本。
如果问题没有比我想象的更多,那么它应该不会复杂。
假设
VersionID
是唯一标识符,那么你可以这样做:
var existingVersions = db.ExistingVersions.Select(x => x.VersionID).ToList();
请注意,对于
Contains
最好:
var existingVersions = new HashSet(db.ExistingVersions.Select(x => x.VersionID).ToList());
[编辑]: 根据 Magnus 的评论,您可以从上面的代码片段中删除
ToList
。
然后:
var newVersions = items.Versions.Where(x => !existingVersions.Contains(x.VersionID));
这可能是性能最高的,因为调用数据库时,您仅选择
VersionID
。其他选项包括编写自定义 IEqualityComparer<T>
并使用 Except
,但您必须从数据库中提取所有内容,这可能会更昂贵。
你可以尝试这样的事情:
// in memory: get list of potential version ids
var potentialIds = item.Versions.Select( o => o.versionID ).ToList();
// hit database ( once ) : get existing version ids
var existingIds = db.ExistingVersions
.Where( o => potentialIds.Contains( o.versionID ) )
.Select( o => o.versionID )
.ToList();
// in memory: filter potential objects
var newVersions = item.Versions
.Where( o => !existingIds.Contains( o.versionID ) )
.ToList();
// database inserts:
foreach( var newVersion in newVersions )
{
...
要记住的一件事是,这不是线程安全的:如果其他东西同时添加
ExistingVersion
行,您可以尝试插入在检查数据库后添加的记录。
public async Task<bool> IsExistBy(List<int> ids, CancellationToken ct)
{
var temp = await _repository.TableNoTracking.Where(x=>ids.Contains(x.Id)).ToListAsync(ct);
return temp.Count == ids.Count;
}