fre*_*hie 14 .net c# linq linq-to-sql
我有一个看起来像这样的表:
FruitID | FruitType
23 | 2
215 | 2
256 | 1
643 | 3
Run Code Online (Sandbox Code Playgroud)
我希望通过FruitType给出一个FruitIDs被调用的列表来获得计数TheFruitIDs.这就是我所拥有的:
var TheCounter = (from f in MyDC.Fruits
where TheFruitIDs.Contains(f.FruitID)
group f by 0 into TheFruits
select new MyCounterMode()
{
CountType1 = (int?) TheFruits.Where(f => f.FruitType == 1).Count() ?? 0,
CountType2 = (int?) TheFruits.Where(f => f.FruitType == 2).Count() ?? 0,
.... all the way to CountType6
}).Single();
Run Code Online (Sandbox Code Playgroud)
此代码有效,但问题是有时我会收到超时错误,因为查询运行时间过长.如何更改此代码以避免超时问题?
查询的最简单方法是分组FruitType,然后计算行数:
var countsDictionary = MyDC
.Fruits
.Where(f => TheFruitIDs.Contains(f.FruitID))
.GroupBy(
f => f.FruitType,
(fruitType, fruits) => new { FruitType = fruitType, Count = fruits.Count() }
)
.ToDictionary(c => c.FruitType, c => c.Count);
Run Code Online (Sandbox Code Playgroud)
这将有效地创建以下字典(假设部件不排除任何数据where):
FruitType | Count ----------+------ 1 | 1 2 | 2 3 | 1
如果您真的想将其折叠为具有特定水果类型计数的单个对象,则必须创建此对象:
var TheCounter = new {
CountType1 = countsDictionary.ContainsKey(1) ? countsDictionary[1] : 0,
CountType2 = countsDictionary.ContainsKey(2) ? countsDictionary[2] : 0,
CountType3 = countsDictionary.ContainsKey(3) ? countsDictionary[3] : 0
};
Run Code Online (Sandbox Code Playgroud)
您的查询中还有另一件事可能导致性能问题,可能导致超时:部件中的水果ID列表where包含在查询中,如果该列表非常大,则可能会降低查询速度.除非您从先前的查询到数据库创建此列表,否则您无能为力.在这种情况下,您应该尽量避免将水果ID列表拉到客户端.相反,您应该将选择ID的查询与计算类型的查询相结合.这将确保整个查询在服务器端执行.
您似乎关心代码的结构变化.只要您创建匿名对象,就很难编写可重用的代码.您可以考虑使用带有计数或类似内容的字典.另一种选择是使用计数创建动态对象.就个人而言,我不喜欢这个解决方案,但你可能会发现它很有用.
要简化代码,需要一个存储计数的类:
class TypeCount {
public TypeCount(Int32 type, Int32 count) {
Type = type;
Count = count;
}
public Int32 Type { get; private set; }
public Int32 Count { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
具有属性的动态对象CountType0,CountType1,CountType2基于元组序列等:
class CountsDictionary : DynamicObject {
readonly IDictionary<Int32, Int32> counts;
public CountsDictionary(IEnumerable<TypeCount> typeCounts) {
if (typeCounts== null)
throw new ArgumentNullException("typeCounts");
this.counts = typeCounts.ToDictionary(c => c.Type, c => c.Count);
}
public override Boolean TryGetMember(GetMemberBinder binder, out Object result) {
Int32 value;
if (binder.Name.StartsWith("CountType") && Int32.TryParse(binder.Name.Substring(9), NumberStyles.None, CultureInfo.InvariantCulture, out value) && value >= 0) {
result = this.counts.ContainsKey(value) ? this.counts[value] : 0;
return true;
}
result = 0;
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
一种创建动态对象的扩展方法:
static class CountExtensions {
public static dynamic ToCounts(this IEnumerable<TypeCount> typeCounts) {
return new CountsDictionary(typeCounts);
}
}
Run Code Online (Sandbox Code Playgroud)
把它们放在一起:
var counts = MyDC
.Fruits
.Where(f => TheFruitIDs.Contains(f.FruitID))
.GroupBy(
f => f.FruitType,
(fruitType, fruits) => new TypeCount(fruitType, fruits.Count())
)
.ToCounts();
Run Code Online (Sandbox Code Playgroud)
然后counts.CountType1,您可以检索属性,counts.CountType2和counts.CountType3.其他count.CountType#属性将返回0.但是,由于counts动态,您将无法获得任何智能感知.