Transformative
SQL is poor at transformations, so we are unaccustomed to thinking about query languages as a tool for converting data from one format to another. Instead, we usually use specialized tools such as XSLT or brute-force techniques to transform data.
LINQ, however, has transformational powers built directly into its syntax. We can compose a LINQ query against a SQL database that effortlessly performs a variety of transforms. For instance, with LINQ it is easy to transform the result of a SQL query into a hierarchical XML document. You can also easily transform one XML document into another with a different structure. SQL data is transformed into a hierarchical set of objects automatically when you use LINQ to SQL. In short, LINQ is very good at transforming data, and this adds a new dimension to our conception of what we can do with a query language.
Listing 3.2 shows code that takes the results of a query against relational data and transforms it into XML.
Listing 3.2. A Simple Query That Transforms the Results of a LINQ to SQL Query into XML
var query = new XElement("Orders", from c in db.Customers where c.City == "Paris" select new XElement("Order", new XAttribute("Address", c.Address), new XAttribute("City", c.City)));
Embedded in this query is a simple LINQ to SQL query that returns the Address and City fields from all the customers who live in Paris. In Listing 3.3 I’ve stripped away the LINQ to XML code from Listing 3.2 to show you the underlying LINQ to SQL query.
Listing 3.3. The Simple LINQ to SQL Query Found at the Heart of Listing 3.2
var query = from c in db.Customers where c.City == "Paris" select new { c.Address, c.City };
Here is the output from Listing 3.3:
265, boulevard Charonne 25, rue Lauriston
Here is the output from Listing 3.2:
<Orders> <Order Address="265, boulevard Charonne" City="Paris" /> <Order Address="25, rue Lauriston" City="Paris" /> </Orders>
As you can see, the code in Listing 3.2 performs a transform on the results of the LINQ to SQL query, converting it into XML data.
Because LINQ is composable, the following query could then be used to run a second transform on this data:
var query1 = new XElement("Orders", new XAttribute("City", "Paris"), from x in query.Descendants("Order") where x.Attribute("City").Value == "Paris" select new XElement("Address", x.Attribute("Address").Value));
This query takes the XML results of the first query and transforms that XML into the following format:
<Orders City="Paris"> <Address>265, boulevard Charonne</Address> <Address>25, rue Lauriston</Address> </Orders>
LINQ is constantly transforming one type of data into another type. It takes relational data and transforms it into objects; it takes XML and transforms it into relational data. Because LINQ is extensible, it is at least theoretically possible to use it to tear down the walls that separate any two arbitrary data domains.
Because LINQ is both composable and transformative, you can use it in a number of unexpected ways:
- You can compose multiple queries, linking them in discrete chunks. This often allows you to write code that is easier to understand and maintain than traditional nested SQL queries.
- You can easily transform data from one data source into some other type. For instance, you can transform SQL data into XML.
- Even if you do not switch data sources, you can still transform the shape of data. For instance, you can transform one XML format into another format. If you look back at the section “Declarative: Not How, But What,” you will see that we transformed data that was stored in nested lists into data that was stored in a single list. These kinds of transformations are easy with LINQ.