2010-01-06 3 views
0

Я изучаю LINQ, и это кажется довольно простой проблемой. У меня есть полурабочее решение, но я уверен, что его можно было бы очистить.LINQ to XML with join и GroupBy(). Это верно?

Узел propertyAuto представляет собой автомобиль с идентификатором = 606. Этот узел должен иметь как минимум два дочерних объекта propertyValue, один из которых ссылается на элемент vehicleValuation с атрибутом «Книга» и один из «Авто». (Мой код еще не проверяет это, они оба могут быть Авто или Забронировать)

Наконец, мне нужно получить значение «Книга» и значение «Авто» для того же автомобиля.

Обратите внимание, что я никогда не узнаю никаких идентификаторов или idRef заранее, и в будущем будет несколько автомобилей.

Вот мой код сейчас (готов к копированию в LINQPad!)

var data = XElement.Parse (@" 
<MyXML> 
    <propertyAuto id='606'> 
    <Values> 
     <propertyValue idRef='f95d5dce-8152-4e9e-889e-7433d32664d6' /> 
     <propertyValue idRef='cd1a83a7-dd04-41f9-b31c-5408a38ac777' /> 
    </Values> 
    </propertyAuto> 
    <Valuations> 
    <vehicleValuation id='cd1a83a7-dd04-41f9-b31c-5408a38ac777' 
    valuationType='Auto' estimatedValue='8350.00' /> 
    <vehicleValuation id='f95d5dce-8152-4e9e-889e-7433d32664d6' 
    valuationType='Book' estimatedValue='12475.00' /> 
    </Valuations> 
</MyXML>"); 

var valuations = from property in data.Descendants("propertyValue") 
       join value in data.Descendants("vehicleValuation") 
       on 
        (string)property.Attribute("idRef") 
       equals 
        (string)value.Attribute("id") 
       where property.Parent.Descendants("propertyValue").Count() > 1 
       && ((string)value.Attribute("valuationType") == "Auto" || (string)value.Attribute("valuationType") == "Book")    
       select new { Value = value.Attribute("estimatedValue").Value, Type = value.Attribute("valuationType").Value, PropertyID = property.Parent.Parent.Attribute("id").Value }; 

valuations.Dump(); 

var values = valuations.GroupBy(x=> x.PropertyID).FirstOrDefault(); 
string auto = values.Where(x => x.Type == "Auto").Select(x=>x.Value).First().ToString(); 
string book = values.Where(x => x.Type == "Book").Select(x=>x.Value).First().ToString(); 

auto.Dump(); 
book.Dump(); 

Является ли это работоспособным или я должен перейти к XPath, и т.д.?

ответ

1

Очевидно, что ваше решение работоспособно, потому что оно работает! Я также беру бы это немного дальше, чтобы получить результаты в виде списка автомобилей со свойствами, которые можно легко осмотреть:

var carProperties = from propertyAuto in data.Descendants("propertyAuto") 
        select new 
        { 
         Id = propertyAuto.Attributes("id").First().Value, 
         Properties = from property in propertyAuto.Descendants("propertyValue") 
            join value in data.Descendants("vehicleValuation") 
            on property.Attribute("idRef").Value 
            equals value.Attribute("id").Value 
            select new 
            { 
             Value = value.Attribute("estimatedValue").Value, 
             Type = value.Attribute("valuationType").Value, 
             PropertyID = property.Parent.Parent.Attribute("id").Value 
            } 
        }; 

var cars = from car in carProperties 
      select new 
      { 
       Id = car.Id, 
       Auto = car.Properties.Where(x => x.Type == "Auto").Select(x => x.Value).First(), 
       Book = car.Properties.Where(x => x.Type == "Book").Select(x => x.Value).First() 
      }; 

Обратите внимание, что GroupBy больше не нужен.

1
var valuations = el.Element("Valuations").Elements("vehicleValuation"); 
var carNodes = el.Elements("propertyAuto"); 
var cars = carNodes.Select(x => 
       new { 
        id = x.Attribute("id").Value, 
        PropertyValues = x.Element("Values").Elements("propertyValue"). 
             SelectMany(
               y => valuations.Where( 
                 val => val.Attribute("id").Value == y.Attribute("idRef").Value 
                    ).Select(valuation => 
                      new { 
                       Type = valuation.Attribute("valuationType"), 
                       EstVal = valuation.Attribute("estimatedValue") 
                       } 
                      ) 
               ) 
        }); 

Немного сложно, но это создаст анонимный тип, в котором идентификаторы автомобилей соответствуют значениям свойств.

Если вы хотите, чтобы автомобили автоматически и стоили книгу, вы можете сделать что-то вроде этого.

var cars = carNodes.Select(car => 
       new { 
        id = car.Attribute("id").Value, 
        Auto = car.Element("Values").Elements("propertyValue"). 
             SelectMany(
               y => valuations.Where( 
                 val => val.Attribute("id").Value == y.Attribute("idRef").Value && 
                   val.Attribute("valuationType").Value == "Auto" 
                    ) 
                   .Select(valuation => valuation.Attribute("estimatedValue")) 
               ).SingleOrDefault(), 
        Book = car.Element("Values").Elements("propertyValue"). 
              SelectMany(
                y => valuations.Where(
                  val => val.Attribute("id").Value == y.Attribute("idRef").Value && 
                   val.Attribute("valuationType").Value == "Book" 
                     ) 
                    .Select(valuation => valuation.Attribute("estimatedValue")) 
               ).SingleOrDefault(), 
        });