IEnumerable в LINQ, когда только один экземпляр узла - PullRequest
0 голосов
/ 10 мая 2018

Я пытаюсь запросить XML с помощью Linq.У меня есть следующий фрагмент XML ...

<report>
  <invoice>
    <id>A4245</id>
    <date>12-20-2016</date>
    <amount>12.50</amount>
  </invoice>
<report>

Вот моя модель для хранения данных

public class InvoiceModel
{
  public string InvoiceId { get; set; }
  public string InvoiceDate { get; set; }
  public string InvoiceAmount { get; set; }
}

, а вот запрос LINQ

XDocument xml = XDocument.Parse(@"C:\Path\To\data.xml");
InvoiceModel invoice = xml.Descendants("invoice")
                       .Select(x => new InvoiceModel 
                       {
                         InvoiceId = x.Element("id").Value.ToString(),
                         InvoiceDate = x.Element("date").Value.ToString(),
                         InvoiceAmount = x.Element("amount").Value.ToString()
                       });

Я получаю ошибку ..

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<InvoiceModel>' to 'InvoiceModel'. An explicit conversion exists (are you missing a cast?)

В XML будет только один счет.Как мне сообщить LINQ-запросу, что будет только один экземпляр счета-фактуры и нет необходимости в IEnumerable?

PS Я использую все строки для значений свойств, так как они просто используются как тексти не будет анализироваться.

Ответы [ 4 ]

0 голосов
/ 10 мая 2018

.Select() возвращает коллекцию.Если в этой коллекции будет только один элемент, добавьте:

.Single()

Если их может быть больше одного, и вы хотите первый:

.First()

Если должен быть одинно может быть ни одного:

.SingleOrDefault()

и т. д.

Существует множество логики, которую вы можете применить, с различными методами расширения для любого IEnumerable<T>.По сути, если вам нужен только один, выберите этот из коллекции, возвращаемой .Select().

0 голосов
/ 10 мая 2018

Это происходит потому, что Descendants(...) возвращает IEnumerable<T>, который затем преобразуется с Select в IEnumerable<InvoiceModel>. Если вы знаете, что существует не более одного потомка с правильным именем, используйте FistsOrDefault(), чтобы получить его:

InvoiceModel invoice = xml.Descendants("invoice")
    .Select(x => new InvoiceModel {
        InvoiceId = x.Element("id").Value.ToString(),
        InvoiceDate = x.Element("date").Value.ToString(),
        InvoiceAmount = x.Element("amount").Value.ToString()
    }).FirstOrDefault();
// Make sure that you get an invoice
if (invoice == null) {
    throw new InvalidOperationException("Invoice element does not exist in XML document.");
}
0 голосов
/ 10 мая 2018

Вы можете использовать .FirstOrDefault(), чтобы выбрать единственный элемент invoice:

InvoiceModel invoice = xml.Descendants("invoice")
   .Select(x => new InvoiceModel
   {
       InvoiceId = x.Element("id").Value.ToString(),
       InvoiceDate = x.Element("date").Value.ToString(),
       InvoiceAmount = x.Element("amount").Value.ToString()
   })
   .FirstOrDefault();

В вашем коде есть другие проблемы:

  • Вы хотите использовать XDocument.Load для загрузки файла Parse предназначен для необработанного xml.
  • xml не завершен должным образом.Последний тег должен быть </report>.
0 голосов
/ 10 мая 2018

Попробуйте

XDocument xml = XDocument.Parse(@"C:\Path\To\data.xml");
InvoiceModel invoice = xml.Descendants("invoice")
                       .Select(x => new InvoiceModel 
                       {
                         InvoiceId = x.Element("id").Value.ToString(),
                         InvoiceDate = x.Element("date").Value.ToString(),
                         InvoiceAmount = x.Element("amount").Value.ToString()
                       }).FirstOrDefault();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...