194 Microsoft Visual Studio 2010: A Beginner’s Guide options found after clicking the arrow button to expand Database Tools and then selecting Table And Database Designers is “Prevent saving changes that require table re-creation.” VS will not allow you to save a foreign key change to existing tables. However, by unchecking “Prevent saving changes that require table re-creation,” you’ll be able to save foreign key changes to an existing table. As with so many other features of VS, there are literally dozens of database settings; most are intuitive if you already understand SQL Server. Other options differ, depending on the version of VS you have, and your Options screen might not look the same as Figure 7-10. Now that you know how to create databases, tables, and stored procedures, you’ll need to know how to use your database from code. The rest of this chapter shows you how to use LINQ to work with data. First, we’ll look at the basic syntax of LINQ through LINQ to Objects and then follow with working with SQL Server through LINQ to SQL. Learning Language Integrated Query (LINQ) LINQ is a set of features built into programming languages, such as C# and VB, for working with data. It’s called Language Integrated Query because the LINQ syntax is part of the language, as opposed to being a separate library. This section will show you the essentials of LINQ with LINQ to Objects, a LINQ provider for querying in-memory collections of objects. The great news is that the syntax you learn here is not only applicable to LINQ to Objects, but to all other LINQ providers, such as LINQ to SQL and more, that you’ll encounter. The examples in this chapter will use a Console project for simplicity. Later chapters will show you how to display data in desktop and Web applications. If you want to run the code in this chapter, you can create a Console application and type the examples into the Main method, as has been explained in each previous chapter of this book. Querying Object Collections with LINQ One way to use LINQ is via LINQ to Objects, which allows you to query collections of objects. You can use LINQ to query any collection that implements the IEnumerable interface. As you may recall, we discussed interfaces in Chapter 4; now you can see one more example of how important interfaces are to .NET development. Listing 7-2 shows a program that uses LINQ to query a collection. The object type is a custom class, named Customer. The Main method creates a generic list of Customer and uses a LINQ query to extract the Customer objects that have a first name that starts with the letter M. Chapter 7: Working with Data 195 Listing 7-2 A program demonstrating how to make a LINQ to objects query C#: using System; using System.Collections.Generic; using System.Linq; class Customer { public string FirstName { get; set; } public string LastName { get; set; } } class Program { static void Main(string[] args) { List<Customer> custList = new List<Customer> { new Customer { FirstName = "Joe", LastName = "Zev" }, new Customer { FirstName = "May", LastName = "Lee" }, new Customer { FirstName = "Meg", LastName = "Han" } }; var customers = from cust in custList where cust.FirstName.StartsWith("M") select cust; foreach (var cust in customers) { Console.WriteLine(cust.FirstName); } 196 Microsoft Visual Studio 2010: A Beginner’s Guide Console.ReadKey(); } } VB: Class Customer Property FirstName As String Property LastName As String End Class Module Module1 Sub Main() Dim custList As New List(Of Customer) From { New Customer With { .FirstName = "Joe", .LastName = "Zev" }, New Customer With { .FirstName = "May", .LastName = "Lee" }, New Customer With { .FirstName = "Meg", .LastName = "Han" } } Dim customers = From cust In custList Where cust.FirstName.StartsWith("M") Select cust For Each cust In customers Console.WriteLine(cust.FirstName) Next Console.ReadKey() End Sub End Module Chapter 7: Working with Data 197 Both the C# and VB examples from Listing 7-2 contain similar LINQ queries. To clarify, the following examples show both the C# LINQ query: var customers = from cust in custList where cust.FirstName.StartsWith("M") select cust; and the VB LINQ query: Dim customers = From cust In custList Where cust.FirstName.StartsWith("M") Select cust The customers variable in the LINQ queries references a new collection that holds the result of running the LINQ query, which contains all of the customers where the first letter of the FirstName property is the letter M. The from clause specifies the range variable that you name, cust is the name I chose, and the collection object to query, custList, was created and populated in the previous line of code. The range variable is what you use to specify parameters of the LINQ query. In the preceding example, we use the where clause to filter the results of the query. This where clause calls the StartsWith method on each FirstName property of the cust range variable to specify the filter. The select clause specifies that each individual customer object is returned into our new customers collection, which we declared as type var (Dim in VB), which means our customers variable winds up being whatever collection type is returned from our LINQ query. This also means that the resulting customers collection will contain zero or more Customer type instances, depending on the filter we specified and whether our custList contained any Customer objects in the first place as a result of the Select cust portion of the LINQ statement. The select clause for C# queries is required, but the select clause for VB queries is optional and will return the range variable instance if omitted. What our LINQ statement is essentially saying in English is “Create a new collection object and assign it to our variable customers (we don’t really care what type of object customers turns out to be as long as we can use it later), then go through every object in our previously defined and loaded custList collection, selecting only the ones that have for their FirstName property a string that begins with the letter M, and ignore all the rest, then take the ones that match this filter and stuff them into whatever collection you created for me earlier that you assigned to my variable customers.” 198 Microsoft Visual Studio 2010: A Beginner’s Guide Creating a LINQ Projection with Anonymous Types You can customize what is returned by the select clause by using what is called an anonymous type. This customization of return values is called a projection. Anonymous types facilitate custom projections, allowing you to return the results of a LINQ query in a form that you specify without needing to declare a new type ahead of time. Here’s an example of creating a query that declares a new anonymous type for combining the FirstName and LastName properties of Customer into a variable, FullName, that is created as a string-type property associated with the object returned into cust in the foreach statement: C#: var customers = from cust in custList where cust.FirstName.StartsWith("M") select new { FullName = cust.FirstName + " " + cust.LastName }; foreach (var cust in customers) { Console.WriteLine(cust.FullName); } VB: Dim customers = From cust In custList Where cust.FirstName.StartsWith("M") Select New With { .FullName = cust.FirstName & " " & cust.LastName } For Each cust In customers Console.WriteLine(cust.FullName) Next In both the C# and VB select clauses you see a new statement (New With in VB) that defines the anonymous type. The new anonymous type has a single property, FullName, that is the combination of FirstName and LastName in Customer, but the new type will Chapter 7: Working with Data 199 only have a FullName property. Notice how the foreach loop uses the FullName property, instead of the FirstName property from Listing 7-2. The beauty of this anonymous type is that we don’t really care what type of object is generated for us by the LINQ query, as long as that object has the new property associated with it that we specified, FullName in this case, which it does. The variable, cust, in the preceding listing is used in two different scopes: the LINQ query and the foreach statement. Although the identifier, cust, is the same, the two usages are separate instances. Although you might not use the same practice in your own code, I wanted to demonstrate this so that you can see that range variables, such as cust, are scoped to the query they are defined in. Another nuance of the preceding code is that cust, in the foreach loop, is not type Customer. Rather, it is an instance of the anonymous type created by the projection (select clause) of the LINQ query. Therefore, FullName is the only property each anonymous type instance, cust, contains. Using LINQ to Sort Collection Results Another common task you’ll want to perform with data is sorting so that you can put objects in a certain order. The following example modifies the example from Listing 7-2 to sort items from the customer List in descending order: C#: var customers = from cust in custList orderby cust.FirstName descending select cust; VB: Dim customers = From cust In custList Order By cust.FirstName Descending Select cust The orderby (Order By in VB) clause specifies the properties to sort on. This example sorts the list by the FirstName property in descending order. This was a quick taste of what you could do with LINQ, and there is much more. In fact, I wrote an entire book on the subject titled LINQ Programming (McGraw-Hill/ Professional, 2008). The remaining section of this book takes what you’ve learned here and expands, showing you more samples of LINQ queries. The difference will be that you will be working with SQL Server data instead of in-memory objects. 200 Microsoft Visual Studio 2010: A Beginner’s Guide Handling Data with LINQ to SQL The LINQ to SQL provider allows you to communicate with SQL Server databases. There are many other types of providers, such as LINQ to Entities for generic databases (which includes SQL Server), LINQ to XML for XML data sources, and LINQ to Oracle for Oracle databases. The preceding section showed you how to use the in-memory provider, LINQ to Objects. However, LINQ to SQL is the easiest database provider to learn and ships with VS. Once you learn LINQ to SQL, the journey to other providers is easier. The following sections will show you how to set up LINQ to SQL, perform queries, and modify data. Setting Up LINQ to SQL Setting up LINQ to SQL involves running the LINQ to SQL Wizard and adding classes and methods. Behind the scenes, LINQ to SQL generates code, saving you a lot of work. The result of setting up LINQ to SQL is that you will have a data model, which is an environment with classes that you can use to query and modify database data and call methods for invoking stored procedures. Before setting up LINQ to SQL, you’ll need to create a project (a Console project for the purposes of this chapter). See Chapter 5 if you need a refresher on how to set up a Console project. Select Add | New Item, select LINQ to SQL Classes, name the file MyShop.dbml, and click Add. This will show you the LINQ to SQL Designer, with two surfaces for classes and methods. Figure 7-11 shows the LINQ to SQL Designer with a couple of classes and a method. Figure 7-11 The LINQ to SQL Designer . 194 Microsoft Visual Studio 2010: A Beginner’s Guide options found after clicking the arrow button to expand Database. foreach (var cust in customers) { Console.WriteLine(cust.FirstName); } 196 Microsoft Visual Studio 2010: A Beginner’s Guide Console.ReadKey(); } } VB: Class Customer Property FirstName. you created for me earlier that you assigned to my variable customers.” 198 Microsoft Visual Studio 2010: A Beginner’s Guide Creating a LINQ Projection with Anonymous Types You can customize