C#Linq快速计算列表中项目的有效方法
本文关键字:项目 有效 方法 列表 计算 C#Linq | 更新日期: 2023-09-27 18:01:00
我正在使用带有EF的Linq to Entities,并希望有一种有效的方法来做到这一点。我正在做的是浏览一个列表,计算列表中不同的项目,将计数附加到一个元素上,并使用string.Join返回一个字符串
一(3(、二(1(、三(2(
从具有类似的项目的列表
一二一二一
如果我没有从我的POCO类中检索,并为数据库中的每个条目动态处理所有这些,并将列表传递给我的DataGridView,这会更简单。
我的代码是这样的,
public class Module
{
//Other fields here
public string PartNumber { get; set; }
[ForeignKey("PartNumber")]
public Part Part { get; set; }
[ForeignKey("Location")]
public string WarehouseID { get; set; }
public Warehouse Location { get; set; }
}
还有另一个
public class Warehouse
{
//Other fields here
public List<Module> Modules { get; set; }
}
然后是POCO类,我在其中检索列表,对于每个实体,我都会得到一个绑定到我的datagridview的字符串。
public class Part{
//Other fields
public string Locations
{
get
{
//I don't know how efficient this is but I feel that it helps
if (Modules.Count() < 1)
return "";
AirtelDataContext context = new AirtelDataContext();
var modules = context.Modules.Include("Location")
.Where(e => e.PartNumber == PartNumber && e.Location.WarehouseType != "Site")
.Select(a => a.Location.WarehouseName)
.ToList();
var q = from x in modules
group x by x into g
let count = g.Count()
orderby count descending
select (g.Key + " (" + count + ")").ToString();
return String.Join(", ", q);
}
}
}
正是这个只读的位置属性,我想提高它的效率。我的数据库(MySql(将容纳少于7000个(可能最多2000个部件实体、2000个仓库主体和最多5000个模块实体(
如果我能稍微提高一点表现,我将不胜感激。将零件实体加载到DataGridView需要超过10秒的时间。
您可以尝试将查询推送到服务器,方法是不对前一个查询调用ToList
:
var modules = context.Modules.Include("Location")
.Where(e => e.PartNumber == PartNumber &&
e.Location.WarehouseType != "Site")
.Select(a => a.Location.WarehouseName);
//.ToList();
var q = from x in modules
group x by x into g
let count = g.Count()
orderby count descending
select (g.Key + " (" + count + ")").ToString();
或者只需将分组和计数合并为一个查询:
var modules = context.Modules.Include("Location")
.Where(e => e.PartNumber == PartNumber &&
e.Location.WarehouseType != "Site")
.GroupBy(a => a.Location.WarehouseName);
.Select(g => g.Key + " (" + g.Count() + ")");
编辑
由于您处理的是EF,它不能直接将您的投影转换为SQL,因此您的下一个选择是在SQL中执行分组,并在Linq中将字符串连接为Objects:
var modules = context.Modules.Include("Location")
.Where(e => e.PartNumber == PartNumber &&
e.Location.WarehouseType != "Site")
.GroupBy(a => a.Location.WarehouseName);
.Select(g => new {g.Key, Count = g.Count()})
.AsEnumerable() // shift to linq-to-objects
.Select(g => g.Key + " (" + g.Count + ")");
这是你需要正确学习的关于GroupBy((、Count((和OrderBy((的一切,你并不绝对需要使用var的查询。一切都可以通过链接EF函数来完成,请参阅:
https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
@DStanley是对的,在这一点上不应该调用ToList
方法,因为它将立即执行您的第一个查询,而第二部分(分组和选择(将在内存中使用Linq to Objects执行。如果您合并两个查询,您可以在MySql数据库上远程执行所需的所有内容,因此,这将提高性能:
var q = from x in context.Modules.Include("Location")
where x.PartNumber == PartNumber && x.Location.WarehouseType != "Site"
group x by x.Location.WarehouseName into g
let count = g.Count()
orderby count descending
select g.Key + " (" + count + ")";
此时,如果您想将结果保存到内存中,可以调用ToList
方法:
var distincItems=q.ToList();