我遇到的情况是循环LINQ的结果让我很紧张。那么这就是我的情景:
我有一个来自数据库的DataTable,我从中获取数据:
var results = from d in dtAllData.AsEnumerable()
select new MyType
{
ID = d.Field<Decimal>("ID"),
Name = d.Field<string>("Name")
}
根据排序顺序执行订单后:
if(orderBy != "")
{
string[] ord = orderBy.Split(' ');
if (ord != null && ord.Length == 2 && ord[0] != "")
{
if (ord[1].ToLower() != "desc")
{
results = from sorted in results
orderby GetPropertyValue(sorted, ord[0])
select sorted;
}
else
{
results = from sorted in results
orderby GetPropertyValue(sorted, ord[0]) descending
select sorted;
}
}
}
GetPropertyValue方法如下:
private object GetPropertyValue(object obj, string property)
{
System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}
在此之后,我将为第一页取出25条记录,如:
results = from sorted in results
.Skip(0)
.Take(25)
select sorted;
到目前为止事情进展顺利,现在我必须将这个结果传递给一个方法,该方法将对数据进行一些操作并返回所需的数据,这里我想循环这25条记录花了足够的时间。我的方法定义是:
public MyTypeCollection GetMyTypes(IEnumerable<MyType> myData, String dateFormat, String offset)
我已经尝试foreach
并且在我的机器上需要8-10秒,这需要时间:
foreach(var _data in myData)
我尝试了while循环并且正在做同样的事情,我使用它像:
var enumerator = myData.GetEnumerator();
while(enumerator.MoveNext())
{
int n = enumerator.Current;
Console.WriteLine(n);
}
这段代码花时间在MoveNext
比我去for
循环一样:
int length = myData.Count();
for (int i = 0; i < 25;i++ )
{
var temp = myData.ElementAt(i);
}
此代码需要时间ElementAt
任何人都可以指导我,我做错了什么。我在VS 2008中使用Framework 3.5。
提前致谢
答案 0 :(得分:3)
GetPropertyValue
,以便对它们进行排序。
如果你可以在没有反射的情况下做到这一点,那将会更好 ...但如果你做需要使用反射,至少要调用{{1} } 一次而不是每条记录。
(在某些方面,这更多地与帮助您比完整答案更容易诊断问题有关......)
正如亨克所说,这很奇怪:
Type.GetProperty()
你几乎肯定真的只是想要:
results = from sorted in results
.Skip(0)
.Take(25)
select sorted;
(results = results.Take(25);
毫无意义。)
它可能实际上没有帮助,但它会使代码更容易调试。
下一个问题是我们实际上无法看到您的所有代码。你写过:
根据排序顺序执行订单
...但您尚未显示 您正在执行订购的方式。
您应该向我们展示从Skip(0)
到其使用的完整示例。
更改迭代序列的方式将不帮助 - 无论是哪种方式都会做同样的事情 - 尽管令人惊讶的是,在您的上一次尝试中,DataTable
显然很快就能正常工作。坚持Count()
- 但确切地解决了将要做的事情。 LINQ使用了很多懒惰的评估,如果你做了一些非常重要的事情,可能成为问题。没有看到整个管道就很难知道。
答案 1 :(得分:0)
问题是你的“结果”IEnumerable实际上并没有被评估,直到它被传递到你的方法并被枚举。这意味着整个操作,从dtAllData获取所有数据,选择新类型(发生在整个可枚举,而不仅仅是前25个),然后最后是take 25操作,都发生在第一个枚举IEnumerable(foreach,while,无论如何)。
这就是为什么你的方法需要这么长时间。它实际上正在做一些在方法内部定义的工作。如果你希望在你的方法之前发生这种情况,你可以在方法之前做一个“ToList()”。
答案 2 :(得分:0)
您可能会发现采用混合方法更容易;
按顺序:
1)对您的数据表进行原位排序。最好在数据库级别执行此操作,但是,如果不能,那么DataTable.DefaultView.Sort非常有效:
dtAllData.DefaultView.Sort = ord[0] + " " + ord[1];
这假设ord [0]是列名,而ord [1]是ASC或DESC
2)通过索引编辑DefaultView:
int pageStart = 0;
List<DataRowView> pageRows = new List<DataRowView>();
for (int i = pageStart; i < dtAllData.DefaultView.Count; i++ )
{
if(pageStart + 25 > i || i == dtAllData.DefaultView.Count - 1) { break; //Exit if more than the number of pages or at the end of the rows }
pageRows.Add(dtAllData.DefaultView[i]);
}
...并从这个小得多的列表中创建你的对象......(我假设这些列被称为Id和Name,以及类型)
List<MyType> myObjects = new List<MyType>();
foreach(DataRowView pageRow in pageRows)
{
myObjects.Add(new MyObject() { Id = Convert.ToInt32(pageRow["Id"]), Name = Convert.ToString(pageRow["Name"])});
}
然后,您可以继续完成剩下的工作。