我正在使用Linq to Entities with EF,并且想要一种有效的方法来实现这一点。我正在做的是通过列表,计算列表中的不同项,将计数附加到一个元素并使用String.Join返回一个字符串。我想要(而且我实现)就是这个
一(3),二(1),三(2)
来自具有此类项目的列表
一,三,一,三,二,一
如果我没有从我的POCO类中检索并为我的数据库中的每个条目动态处理所有这些并将List传递给我的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秒以上的时间。
答案 0 :(得分:3)
您可以尝试通过不在先前查询上调用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-to-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 + ")");
答案 1 :(得分:2)
这是您正确了解GroupBy(),Count()和OrderBy()所需的一切,您绝对不需要使用var的查询。一切都可以通过链接EF函数来完成,请参阅:
答案 2 :(得分:2)
@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();