我有以下代码从sql数据库中提取客户地址作为纬度/经度点,并在winforms Map上显示点。但是,数据库非常大,这需要很长时间才能完成foreach。
有更好的方法吗?
public static List<MyAppMaps.MapPoints> GetAddresses()
{
List<MyAppMaps.MapPoints> addresses = new List<MyAppMaps.MapPoints>();
try
{
using (DataClassesDataContext dataClassesDataContext = new DataClassesDataContext(cDbConnection.GetConnectionString()))
{
var query = (from customer in dataClassesDataContext.Customers
where (customer.Address.Latitude != ""
|| customer.Address.Longitude != "")
select customer);
if (query.ToList().Count > 0)
{
foreach (Customer item in query)
{
MyAppMaps.MapPoints address = new MyAppMaps.MapPoints();
address.Lat = item.Address.Latitude;
address.Long = item.Address.Longitude;
addresses.Add(address);
}
}
}
}
catch (Exception)
{
}
return addresses;
}
答案 0 :(得分:2)
您可以在LINQ中进行投影,以避免提取您不需要的数据:
var addresses = dataClassesDataContext.Customers.
.Select(c => c.Address)
.Where(a => a.Latitude != "" || a.Longitude != "")
.Select(c => new {
a.Latitude
, a.Longitude
}).AsEnumerable() // From this point on LINQ is in memory
.Select(p => new MyAppMaps.MapPoints {
Lat = p.Latitude, Long = p.Longitude
}).ToList();
此简化版本也可以使用:
var addresses = dataClassesDataContext.Customers.
.Select(c => c.Address)
.Where(a => a.Latitude != "" || a.Longitude != "")
.Select(a => new MyAppMaps.MapPoints {
Lat = a.Latitude, Long = a.Longitude
}).ToList();
答案 1 :(得分:1)
问题是您访问Address
属性,该属性可能指向另一个表,然后在foreach
期间延迟加载(意味着每次迭代会导致另一个查询)。
在使用Entity Framework时,您需要确保避免这种情况。如果您想直接在响应中包含某些内容,请使用Include
方法避免在引擎盖下进行其他查询。但是,通常最好使用Select
投影来真正返回您实际需要的内容,这将使数据传输保持在最低速率。
您应该使用Select
返回您需要的地址:
var query = (from customer in dataClassesDataContext.Customers
where (customer.Address.Latitude != ""
|| customer.Address.Longitude != "")
select customer.Address);
您也可以致电ToList()
检查是否有任何物品。这会不必要地执行查询。您可以立即拨打ToList()
,然后使用创建的列表,或者只使用Any
检查是否确实存在任何包含轻量级查询的项目。
总的来说,您可以改进代码如下:
using (DataClassesDataContext dataClassesDataContext = new DataClassesDataContext(cDbConnection.GetConnectionString()))
{
var query = from customer in dataClassesDataContext.Customers
where (customer.Address.Latitude != ""
|| customer.Address.Longitude != "")
select new MyAppMaps.MapPoints() { Longitude = customer.Address.Longitude, Latitude = customer.Address.Latitude };
addresses.AddRange( query );
}
正如@Evk所建议的那样,只需返回两个必填字段而不是整个Address
实例,即可进一步提高。我已更新代码以反映这一点。
根据@ Sivaprasath的建议进一步简化 - 通过LINQ查询将结果添加到地址列表中。