Последовательность не содержит соответствующий элемент
У меня есть 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;
}
}
}
4 ответа:
Ну, я бы ожидал, что именно эта строка бросает исключение:
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 }
это проще и более эффективный ИМО.
даже если вы do решите держать петлю, у меня есть несколько предложений:
- избавиться от внешних
if
. Вам это не нужно, так как если Count равен нулю, тело цикла for никогда не будет выполнятьсяиспользуйте эксклюзивные верхние границы для циклов - они более идиоматичны C#:
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. First никогда не вернет null - если он не может найти соответствующий элемент, он выдает исключение, которое вы видите.
_dsACL.Documents.FirstOrDefault(o => o.ID == id);