我有一个asp.net应用程序,我在其中使用linq进行数据操作。运行时,我得到异常“序列不包含匹配元素”。
if (_lstAcl.Documents.Count > 0)
{
for (i = 0; i <= _lstAcl.Documents.Count - 1; i++)
{
string id = _lstAcl.Documents[i].ID.ToString();
var documentRow = _dsACL.Documents.First(o => o.ID == id);
if (documentRow !=null)
{
_lstAcl.Documents[i].Read = documentRow.Read;
_lstAcl.Documents[i].ReadRule = documentRow.ReadRule;
_lstAcl.Documents[i].Create= documentRow.Create;
_lstAcl.Documents[i].CreateRule = documentRow.CreateRule;
_lstAcl.Documents[i].Update = documentRow.Update;
_lstAcl.Documents[i].UpdateRule = documentRow.UpdateRule;
_lstAcl.Documents[i].Delete = documentRow.Delete;
_lstAcl.Documents[i].DeleteRule = documentRow.DeleteRule;
}
}
}
好吧,我希望这条线是抛出异常:
var documentRow = _dsACL.Documents.First(o => o.ID == id)
如果First()
找不到任何匹配的元素,它将抛出异常。鉴于您之后立即测试了null,听起来您需要FirstOrDefault()
,如果找不到匹配项,则返回元素类型的默认值(对于引用类型为null):
var documentRow = _dsACL.Documents.FirstOrDefault(o => o.ID == id)
在某些情况下要考虑的其他选项是Single()
(当你相信只有一个匹配元素时)和SingleOrDefault()
(当你相信只有一个或零个匹配元素时)。我怀疑FirstOrDefault
是这个特殊情况下的最佳选择,但无论如何都值得了解其他人。
另一方面,看起来你最初可能会更好地加入这里。如果你不关心它会做所有匹配(而不仅仅是第一次)你可以使用:
var query = from target in _lstAcl.Documents
join source in _dsAcl.Document
where source.ID.ToString() equals target.ID
select new { source, target };
foreach (var pair in query)
{
target.Read = source.Read;
target.ReadRule = source.ReadRule;
// etc
}
这是更简单,更有效的IMO。
即使你决定保持循环,我也有一些建议:
if
。你不需要它,就像Count为零一样,for循环体永远不会执行for (i = 0; i < _lstAcl.Documents.Count; i++)
var target = _lstAcl.Documents[i];
// Now use target for the rest of the loop body
foreach
而不是for
开头:
foreach (var target in _lstAcl.Documents)
使用FirstOrDefault。首先永远不会返回null - 如果它找不到匹配的元素,它会抛出你看到的异常。
_dsACL.Documents.FirstOrDefault(o => o.ID == id);
来自MSDN库:如果source不包含任何元素,则First(IEnumerable)方法会抛出异常。要在源序列为空时返回默认值,请使用FirstOrDefault方法
对于那些在通过上下文菜单创建控制器时遇到此问题的人,以管理员身份重新打开Visual Studio进行修复。
也许在First()之前使用Where()可以帮助你,因为在这种情况下我的问题已经解决了。
var documentRow = _dsACL.Documents.Where(o => o.ID == id).FirstOrDefault();