Using Literal XML with Embedded Expressions in VB9
I spent the week of April 13th in Redmond at the MVP Summit. If you don't know, MVP stands for Most Valuable Professional. One usually becomes and MVP by nomination and then having acquired some unknown amount of community kudos. For instance, lots of blogging and voluntarily helping people in newsgroups might get you there eventually. So, the MVP Summit is a way for Microsoft to thank MVPs for their free contributions, continue to foster affinity with these non-Microsoft employees, and provide MVPs with an insider's look at upcoming features. Thanks, Microsoft.
I have to tell you I was shocked! Shocked at the few very vocal Visual Basic MVPs who sounded like whiiiinnnnneeeerrrrs. (You know who you are.) The gist of it was the people don't treat VB programmers like real programmers or at least on a par with, say, C# programmers. They were right. VB contractors make less than C# contractors in general. But, this is not Microsoft's fault, folks. VB can be a tough, gritty language capable of solving any problem that C# can solve, but there is an underlying problem and it lives in the VB community itself.
Many VB programmers are holding onto old VB6 and the VB6 ways of doing things; consequently, there is no room for new articles, new books, or any reason to really learn anything new. So, if VB is the poor cousin, it's our fault. Personally, I know VB is just as good a language as any out there—well, VB9 anyway. To demonstrate that, this article crams seven cool and a bit complicated—if it's your first time seeing them—features into an 80-line sample program.
In this article, you will get a chance to explore LINQ to SQL, generic delegates, literal XML with embedded LINQ expressions, attributes, and Lambda expressions. (Did I say in 80 lines of code?) In fact, even C# can't do literal XML, which is way cool. So, if you know a holdout in VB6 or someone doing things the same old way, feel sorry for them because these features or too cool, too fun, and promote way too much productivity to ever go back.
Previewing the Technology Usage
The basic setup here is that a lot of data exists in databases. This data is generally read from a database, converted to some form or another, changes are made, and then the data is written back to the database. Sometimes, the data is converted to something highly transmittable, such as text/XML.
In the example in Listing 1, you will see just how easy it is to initialize database entities—classes that map to a database table—with LINQ to SQL, and how with literal XML with embedded expressions can be used to transform the entities into any shape XML tree you need. The supporting cast is comprised of Lambda expressions, generic delegates, and attributes.
Listing 1: An 80-line sample program that uses a lot of cool new capabilities provided by VB9 to do some powerful stuff.
Imports System.Data.Linq Imports System.Data.Linq.Mapping Imports System.Xml.Linq Module Module1 Sub Main() Dim ConvertToXML As Func(Of List(Of Shipper), String) = _ Function(shippers) (<Shippers> <%= From shipper In shippers _ Select <Shipper ShipperID=<%= shipper.ShipperID %> <%= shipper.CompanyName %>> <Phone><%= shipper.Phone %></Phone></Shipper> %> </Shippers>).ToString() Dim northwind As Northwind = New Northwind Console.WriteLine(ConvertToXml(northwind.Shippers.ToList())) Console.ReadLine() End Sub End Module Public Class Northwind Inherits DataContext Private Shared ReadOnly connectionString As String = _ "Data Source=BUTLER;Initial Catalog= _ Northwind;Integrated Security=True" Public Sub New() MyBase.New(connectionString) End Sub Public ReadOnly Property Shippers() As Table(Of Shipper) Get Return Me.GetTable(Of Shipper)() End Get End Property End Class <Table(Name:="Shippers")> _ Public Class Shipper Private _shipperID As Integer <Column(Storage:="_shipperID")> _ Public Property ShipperID() As Integer Get Return _shipperID End Get Set(ByVal Value As Integer) _shipperID = Value End Set End Property Private _companyName As String <Column(Storage:="_companyName")> _ Public Property CompanyName() As String Get Return _companyName End Get Set(ByVal Value As String) _companyName = Value End Set End Property Private _phone As String <Column(Storage:="_phone")> _ Public Property Phone() As String Get Return _phone End Get Set(ByVal Value As String) _phone = Value End Set End Property End Class