我有一个.Net后端,它允许我通过相应的客户端API通过.Id和.Revision属性查询项目,甚至更好,通过提供这些组合的列表批量查询。
但是,每个.Id可能只出现一次每个查询但输入 包含多个具有相同ID的条目多次,但具有不同的.Revision值,例如:
.Id | .Revision
1 | 1
1 | 2
2 | 1 (unique .Id)
3 | 3
3 | 5
4 | 2 (unique .Id)
5 | 1 (unique .Id)
..所以基本上.Id 1和3的条目会导致问题,我想知道检索所有组合的最有效方式(=最少量的查询)是什么。
最糟糕的情况是运行时明智但最容易实现的是逐个检索所有组合而忽略潜在的批量/批处理机制,但即使这将在逻辑上返回正确的项目集,但它显然很慢。 / p>
我如何获得最大的unqiue .Id / .Revision组合,并将剩余的多个.Id-ones组合在一起,以最少的批量生效?
答案 0 :(得分:2)
你应该能够在一个循环中使用一些LINQ表达式相对容易地做到这一点。
例如,假设您有一个Item
类,如下所示:
public class Item
{
public int Id { get; set; }
public int Rev { get; set; }
}
以及要批量查询的List<Item> Items;
列表。在批处理中,Id
不能多次出现。
您可以使用Distinct
轻松获得第一个查询:
var queryItems = Items.Distinct(new ItemIdComparer()).ToList();
你的比较者:
public class ItemIdComparer: IEqualityComparer<Item>
{
public int Equals(Item x, Item y)
{
return x.Id == y.Id;
}
public int GetHashCode(Item x)
{
return x.Id;
}
}
但现在你需要留下的物品。为此,您还需要一个将修订考虑在内的相等比较器:
public class ItemComparer: IEqualityComparer<Item>
{
public int Equals(Item x, Item y)
{
return x.Id == y.Id && x.Rev == y.Rev;
}
public int GetHashCode(Item x)
{
// not the best hash code, but should work okay.
return x.Id ^ x.Rev;
}
}
要获取原始列表中但不在不同列表中的项目列表,请致电Enumerable.Except:
var leftover = Items.Except(queryItems, new ItemComparer()).ToList();
如果你把它放在一个循环中,你可以反复这样做,直到leftover
列表为空:
var workingItems = Items.ToList();
while (workingItems.Count > 0)
{
var queryItems = workingItems.Distinct(new ItemIdComparer()).ToList();
var leftover = workingItems.Except(queryItems, new ItemComparer()).ToList();
DoQuery(queryItems);
workingItems = leftover;
}
使用此算法,您只需两次查询即可获取所有项目的信息。第一个将得到项目1.1,2.1,3.3,4.2和5.1。第二个查询将获得1.2和3.5。
答案 1 :(得分:1)
给出这种格式的条目列表:
public class Entry
{
public int Id { get; set; }
public int Version { get; set; }
}
如何按ID分组,然后为标记为批号的每个条目投射一个新的元素列表,其中包含Id,Version和rank?排名将在具有相同Id的所有条目中。然后,您可以使用相同的批次编号对所有条目进行分组,并一次提交一个批次。
这是我的表达:
var entries = GenerateEntries();
var result = entries
.GroupBy(e => e.Id)
//project new entries with a batch number
.SelectMany(g => g.Select((e, i) => new { Id = e.Id, Version = e.Version, Batch = i }))
.GroupBy(e => e.Batch);