views:

334

answers:

2

I'm converting the Linq query below from C# to VB.Net. Can you spot my error? The query joins 3 XML datasets. Thanks in advance!

C# - This one works great.

List<Course> courses =
  (from course in CourseXML.Descendants(ns + "row")
  join coursecategory in CourseCategoryXML.Descendants("Table") on (string)course.Attribute("code") equals (string)coursecategory.Element("DATA")
  join category in CategoryXML.Descendants("Table") on (string)coursecategory.Element("GRP") equals (string)category.Element("GRP")
  where (string)coursecategory.Element("RECTYPE") == "C"
  select new Course {
    CategoryCode = category.Element("GRP").Value,
      Code = course.Attribute("code").Value
  }).ToList<Course>();

VB - I'm getting no results from this, so I suspect I'm either casting improperly or joining improperly.

Dim result = (From course In CourseXML.Descendants(ns + "row") _
Join coursecategory In CourseCategoryXML.Descendants("Table") On CType(course.Attribute("code"), String) Equals CType(coursecategory.Element("DATA"), String) _
Join category In CategoryXML.Descendants("Table") On CType(coursecategory.Element("GRP"), String) Equals CType(category.Element("GRP"), String) _
Where CType(coursecategory.Element("RECTYPE"), String) = "C" _
Select New Course() With _ 
{ _
  .CategoryCode = category.Element("GRP").Value, _
  .Code = course.Attribute("code").Value _
}).ToList()
A: 

You are getting different results because of the casts.

coursecategory.Element("RECTYPE").Value returns a different result than
(string)coursecategory.Element("RECTYPE") == "C" (and obviously CType(coursecategory.Element("RECTYPE"), String) = "C").

If one of your elements is missing a child RECTYPE node, you will not have any results if you properly cast it, which you did in VB.NET.

In C# you didn't cast (string)coursecategory.Element("RECTYPE") == "C" right. If you use ToString() or .Value you would get the correct results.

Use coursecategory.Element("RECTYPE").Value instead, and avoid the casts altogether.

You could test this by changing your select to return:

select new { 
Wrong = (string)coursecategory.Element("RECTYPE"),  // No exception ... incorrect result!
//Maybe = coursecategory.Element("RECTYPE").ToString() //throws NullReferenceException
//Right = (string)coursecategory.Element("RECTYPE").Value // throws NullReferenceException because of a missing element.
CategoryCode = category.Element("GRP").Value,      
Code = course.Attribute("code").Value

});

Richard Hein
`XElement` has `static explicit operator string(XElement)` defined in it, so `(string)Element("Foo")` is exactly equivalent to `Element("Foo").ToString()`, except that the former won't throw on `null`.
Pavel Minaev
... sorry, equivalent to `Element().Value`.
Pavel Minaev
I tested the code on data they are not equivalent.
Richard Hein
"(string)Element("Foo") is exactly equivalent to Element("Foo").ToString(), except that the former won't throw on null", so therefore they are not exactly equivalent and you've proven my point.
Richard Hein
Thanks for the reply Richard, I actually found my call to the method this Linq query is in was bogus so the issue wasn't even with the query itself. However, regarding throwing an exception, I'd actually prefer the joins operate like an inner join. So which solution are you suggesting in that case?
Cory House
+1  A: 

I used the following site to convert: http://www.developerfusion.com/tools/convert/csharp-to-vb/

Dim courses As List(Of Course) = (From course In CourseXML.Descendants(ns & "row") _
    Join coursecategory In CourseCategoryXML.Descendants("Table") On DirectCast(course.Attribute("code"), String) = DirectCast(coursecategory.Element("DATA"), String) _
    Join category In CategoryXML.Descendants("Table") On DirectCast(coursecategory.Element("GRP"), String) = DirectCast(category.Element("GRP"), String) _
    Where DirectCast(coursecategory.Element("RECTYPE"), String) = "C" _
    Select New Course()).ToList(Of Course)()

The main difference is the last Select.

Jim
I actually used the same site for the initial conversion. Very handy. However, the current tool doesn't deal well with LINQ yet. But +1 since this is certainly a relevant site for others.
Cory House