从IEnumerable中选择项目

3

可能是重复问题:
查询结果不能被多次枚举?

我正在使用实体框架(Entity Framework)通过存储过程从我的数据库中选择和返回一组实体。

var results = dataContext.loadData(testargument);

我希望能够计算返回的数据集(以确保只返回一个记录),然后取出列表中的第一个项目。

if(results.Count() == 1)
{
    ReturnedEntity entity = results.First();
}

然而,当我进行这个调用时,我会得到错误信息“查询结果不能被枚举多次”。有谁知道我如何正确地做这件事吗?我猜想调用Count()方法会改变数据,并且不确定是否需要在调用First()方法之前将其放回列表中。我已经尝试过results.ToList().First(),但是仍然得到相同的错误。
此外,我注意到如果对一个空集合调用First()方法,我会得到一个错误,这就是为什么我要确保只返回1条记录的原因。

如果你阅读了有关延迟执行的相关内容,那么这将会更加容易理解:http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx - Richard Ev
6个回答

3

您可以使用 ToList() 来避免这个问题。因为当您将列表加载到内存中后,就可以随心所欲地操作。但我建议您使用 FirstOrDefault()

var results = dataContext.loadData(testargument).ToList();

并且

ReturnedEntity entity = results.FirstOrDefault();

或者
if(results.Length == 1)
    ReturnedEntity entity = results.First();

FirstOrDefault()不是更好的方法。它只是更常用而已。当我知道或者期望序列至少有一个元素时,我会使用First。换句话说,在序列为空时是异常情况。 - Michael Schnerring
OP希望确保只返回一个结果,而不是一个或多个结果。因此,“Single”更合适。 - Jodrell

0

ReturnedEntity entity = results.First();

如果 (entity != null)


2
如果没有结果,这将无法工作,First会抛出一个异常。他需要使用FirstOrDefault - Steve Danner
如果结果为空,它将抛出一个“InvalidOperationException”而不是返回null。 - Jodrell

0

IEnumerable 不支持此操作,这是设计上的限制。 IEnumerable 使用惰性求值来获取您在需要它们之前请求的元素。

如果您想要知道项目数量而不必迭代它们,则可以使用 IList<T>,它具有 Count 属性。


0
尝试在获取计数之前调用.ToList(),因为这将枚举结果。
var resultList = results.ToList();
if(resultList.Count == 1)
{
    ReturnedEntity entity = resultList.First();
}

1
可以使用List的索引访问器,即resultList[0],虽然原方法可行但可能会更快。 - Jodrell

0
var resultList = results.ToList();
if(resultList.Count == 1)
{
    ReturnedEntity entity = resultList.First();
}

-1

我认为

try
{
    var result = dataContext.loadData(testargument).Single()
}
catch (InvalidOperationException)
{
    // Oops not a single result
}

如果获取一个结果之外的更多或更少的结果是异常情况,那么这是更好的方法。如果在正常执行中出现了一个以上或一个以下的结果,则可以执行以下操作

var result = dataContext.loadData(testargument).SingleOrDefault()

if (result != null)
{
    // Continue as usual
}
else
{
   // Oops, not a single result
}

如果您需要重复使用集合,可以使用ToList扩展方法。
var results = dataContext.loadData(testargument).ToList(); 

if(results.Count == 1) 
{     
    ReturnedEntity entity = results[0];
}
else
{
    // Oops, not a single result
}

IList 支持多次枚举,具有 Count 属性和索引访问器,IEnumerable 不支持。


1
如果投反对票的人想要发表评论,我可能会学到一些东西。 - Jodrell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接