Linq To SQL Hands On Lab

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 24

LINQ to SQL: Language Integrated Query over SQL Server

Hands-on Lab
November 2007 For the latest information, please see www.microsoft.com/vstudio

Information in this document is subject to change without notice. The example companies, organizations, products, people, and events depicted herein are fictitious. No association with any real company, organization, product, person or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarked, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

2007 Microsoft Corporation. All rights reserved.

Microsoft, MS-DOS, MS, Windows, Windows NT, MSDN, Active Directory, BizTalk, SQL Server, SharePoint, Outlook, PowerPoint, FrontPage, Visual Basic, Visual C++, Visual J++, Visual InterDev, Visual SourceSafe, Visual C#, Visual J#, and Visual Studio are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries.

Other product and company names herein may be the trademarks of their respective owners.

Page i

Contents
LAB 1: LINQ TO SQL: DATABASE LANGUAGE INTEGRATED QUERIES............................................................1 Lab Objective........................................................................................................................................................1 Exercise 1 Creating your first LINQ to SQL Application......................................................................................2 Task 1 Creating a LINQ Project.....................................................................................................................2 Task 2 - Adding a reference to the System.Data.Linq assembly........................................................................3 Task 3 Mapping Northwind Customers..........................................................................................................3 Task 4 Querying Database Data....................................................................................................................4 Task 5 Exploring the IDE...............................................................................................................................6 Exercise 2 Creating an Object Model.................................................................................................................7 Task 1 Creating the order entity.....................................................................................................................7 Task 2 Mapping Relationships ......................................................................................................................8 Task 3 Strongly Typing the DataContext Object...........................................................................................10 Exercise 3 Using Code Generation to Create the Object Model...........................................................................10 Task 1 - Adding a LINQ to SQL Classes file....................................................................................................10 Task 2 Create your object model.................................................................................................................11 Task 3 Querying your object model..............................................................................................................12 Task 4 Mapping a stored procedure.............................................................................................................13 Task 5 Retrieving new results......................................................................................................................14 Exercise 4 Modifying Database Data................................................................................................................15 Task 1 Modifying your object model.............................................................................................................15 Task 2 Creating a new Entity.......................................................................................................................16 Task 3 Updating an Entity............................................................................................................................16 Task 4 Deleting an Entity.............................................................................................................................17 Task 5 Submitting changes..........................................................................................................................18 Task 6 Using Transactions...........................................................................................................................19

Page ii

Lab 1: LINQ TO SQL: Database Language Integrated Queries


This lab shows how to access relational data using LINQ to SQL. You will start by creating an object model for the Northwind database, and then use the object model to access the database using the new C# 3.0 query expressions and LINQ to SQL APIs. You will next create an object model from an existing database using the LINQ to SQL Designer. This part covers mapping relationships across tables and using Create, Update, and Delete operations. Use of the object model covers the use of transactions, object loading options, stored procedure integration and object identity with LINQ to SQL. LINQ to SQL is a language-agnostic component of the LINQ Project. This is C# version of the lab but LINQ to SQL can be used just as well with the LINQ-enabled version of the Visual Basic compiler. The LINQ Project relies on new keywords and syntax introduced with C# 3.0 available in Visual Studio 2008. This gives us the opportunity to use new IDE features like the integrated debugger, IntelliSense, and instant syntax check.

Lab Objective
Estimated time to complete this lab: 60 minutes The objective of this lab is to learn how LINQ to SQL can be used for accessing relational data. This covers: 1. Creation of an object model from the database and customization of mapping between objects and tables; and 2. Data access tasks often called CRUD operations an acronym for Create, Retrieve, Update, and Delete operations. These tasks can be performed with a simple API without creating explicit SQL insert/update/delete commands. Exercise 1 Creating your first LINQ to SQL application Exercise 2 Creating an object model from a database Exercise 3 Using code generation to create the object model Exercise 4 Modifying database data

In this exercise, you will learn how to map a class to a database table, and how to retrieve objects from the underlying table using LINQ.

Page 1

These exercises require the Northwind database. Please follow the instructions in the LINQ to SQL section of the Essence of LINQ paper to get set up with Northwind before proceeding.

Exercise 1 Creating your first LINQ to SQL Application


In this exercise, you will learn how to map a class to a database table, and how to retrieve objects from the underlying table using LINQ. Task 1 Creating a LINQ Project
1.

Click the Start | Programs | Microsoft Visual Studio 2008 | Microsoft Visual Studio 2008 menu command. In Microsoft Visual Studio, click the File | New | Project menu command In the New Project dialog, in Visual C# | Templates, click Console Application Provide a name for the new solution by entering LINQ to SQL HOL in the Name field Click OK

2. 3. 4. 5.

Page 2

Task 2 - Adding a reference to the System.Data.Linq assembly


1. 2. 3. 4.

In Microsoft Visual Studio, click the Project | Add Reference menu command In the Add Reference dialog make sure the .NET tab is selected click System.Data.Linq assembly Click OK

In Program.cs import the relevant LINQ to SQL namespaces by adding the following lines just before the namespace declaration:
using System.Data.Linq; using System.Data.Linq.Mapping;

Task 3 Mapping Northwind Customers


1.

Create an entity class to map to the Customer table by entering the following code in Program.cs (put the Customer class declaration immediately above the Program class declaration):
[Table(Name = "Customers")] public class Customer { [Column(IsPrimaryKey = true)] public string CustomerID; }

The Table attribute maps a class to a database table. The Column attribute then maps each field to a table column. In the Customers table, CustomerID is the primary key and it will be used to establish the identity of the mapped object. This is accomplished by setting the IsPrimaryKey parameter to true. An object mapped to the database through a unique key is referred to as an entity. In this example, instances of Customer class are entities.
2.

Add the following code to declare a City property:


[Table(Name = "Customers")] public class Customer { [Column(IsPrimaryKey = true)] public string CustomerID; private string _City; [Column(Storage = "_City")] public string City { get { return this._City; } set { this._City = value; } } }

Page 3

Fields can be mapped to columns as shown in the previous step, but in most cases properties would be used instead. When declaring public properties, you must specify the corresponding storage field using the Storage parameter of the Column attribute.
3.

Enter the following code within the Main method to create a typed view of the Northwind database and establish a connection between the underlying database and the code-based data structures:
static void Main(string[] args) { // Use a standard connection string DataContext db = new DataContext(@"Data Source=.\sqlexpress;Initial Catalog=Northwind"); // Get a typed table to run queries Table<Customer> Customers = db.GetTable<Customer>(); }

You need to replace the connection string here with the correct string for your specific connection to Northwind. You will see later that after generating strongly typed classes with the designer, it is not necessary to embed the connection string directly in your code like this. The Customers table acts as the logical, typed table for queries. It does not physically contain all the rows from the underlying table but acts as a typed proxy for the table . The next step retrieves data from the database using the DataContext object, the main conduit through which objects are retrieved from the database and changes are submitted. Task 4 Querying Database Data
1.

Although the database connection has been established, no data is actually retrieved until a query is executed. This is known as lazy or deferred evaluation. Add the following query for London-based customers:
static void Main(string[] args) { // Use a standard connection string DataContext db = new DataContext(@"Data Source=.\sqlexpress;Initial Catalog=Northwind"); // Get a typed table to run queries Table<Customer> Customers = db.GetTable<Customer>(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; // Query for customers in London var custs = from c in Customers where c.City == "London" select c; }

Page 4

This query, which returns all of the customers from London defined in the Customers table, is expressed in query expression syntax, which the compiler will translate into explicit method-based syntax. Notice that the type for custs is not declared. This is a convenient feature of C# 3.0 that allows you to rely on the compiler to infer the correct data type while ensuring strong typing. This is especially useful since queries can return complex multi-property types that the compiler will infer for you, with no need for explicit declaration.
2.

Add the following code to execute the query and print the results:
static void Main(string[] args) { // Use a standard connection string DataContext db = new DataContext(@"Data Source=.\sqlexpress;Initial Catalog=Northwind"); // Get a typed table to run queries Table<Customer> Customers = db.GetTable<Customer>(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; // Query for customers in London var custs = from c in Customers where c.City == "London" select c; foreach (var cust in custs) { Console.WriteLine("ID={0}, City={1}", cust.CustomerID, cust.City); } Console.ReadLine(); }

The example in step 1 of task 3 shows a query. The query is only executed when the code above consumes the results. At that point, a corresponding SQL command is executed and objects are materialized. This concept, called lazy evaluation, allows queries to be composed without incurring the cost of an immediate round-trip to the database for query execution and object materialization. Query expressions are not evaluated until the results are needed. The code above results in the execution of the query defined in step 1 of task 3.
3. 4.

Press F5 to debug the solution Press ENTER to exit the application

The call to the Console.ReadLine method prevents the console window from disappearing immediately. In subsequent tasks, this step will not be stated explicitly.

You should see a console window that looks like this:

Page 5

The first part of the screen shows the log of the SQL command generated by LINQ and sent to the database. You can then see the results of our query. Notice that that the rows retrieved from the db are transformed into real CLR objects. This can be confirmed using the debugger. Task 5 Exploring the IDE
1. 2. 3. 4.

In the C# editor select the Console.WriteLine line inside the foreach loop In Microsoft Visual Studio, click the Debug | Toggle breakpoint menu command (or click F9) Press F5 to debug the application When the debugger stops the execution look at the locals window (or press Ctrl+D,L if the window doesnt appear) Inspect the variable cust to see its properties

5.

Page 6

You can also move the mouse over the variables and see how the IDE is fully aware of the type of the objects we have created.

Exercise 2 Creating an Object Model


In this exercise, you will learn how to create a simple object model. Our first object model will be really simple and composed of two objects mapping to two database tables. Then we will see how to map relationships between objects to foreign key relationships between tables. Task 1 Creating the order entity
1.

After the Customer class definition, create the Order entity class definition with the following code:

[Table(Name = "Orders")] public class Order { private int _OrderID; private string _CustomerID; [Column(Storage = "_OrderID", DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)] public int OrderID { get { return this._OrderID; } // No need to specify a setter because IsDbGenerated is true }

Page 7

[Column(Storage = "_CustomerID", DbType = "NChar(5)")] public string CustomerID { get { return this._CustomerID; } set { this._CustomerID = value; } } }

Task 2 Mapping Relationships


1.

Add a relationship between Orders and Customers with the following code, indicating that Orders.Customer relates as a foreign key to Customers.CustomerID:

[Table(Name = "Orders")] public class Order { private int _OrderID; private string _CustomerID; [Column(Storage = "_OrderID", DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)] public int OrderID { get { return this._OrderID; } // No need to specify a setter because AutoGen is true } [Column(Storage = "_CustomerID", DbType = "NChar(5)")] public string CustomerID { get { return this._CustomerID; } set { this._CustomerID = value; } } private EntityRef<Customer> _Customer; public Order() { this._Customer = new EntityRef<Customer>(); } [Association(Storage = "_Customer", ThisKey = "CustomerID")] public Customer Customer { get { return this._Customer.Entity; } set { this._Customer.Entity = value; } } } LINQ to SQL allows to you express one-to-one and one-to-many relationships using the EntityRef and EntitySet types. The Association attribute is used for mapping a relationship. By creating the association above, you will be able to use the Order.Customer property to relate directly to the appropriate Customer object. By setting this declaratively, you avoid working with foreign key values to associate the corresponding objects manually. The EntityRef type is used in class Order because there is only one customer corresponding to a given Order.
2.

Annotate the Customer class to indicate its relationship to the Order class. This is not strictly necessary, as defining it in either direction is sufficient to create the link; however, it allows you to

Page 8

easily navigate objects in either direction. Add the following code to the Customer class to navigate the association from the other direction:
public class Customer { private EntitySet<Order> _Orders; public Customer() { this._Orders = new EntitySet<Order>(); } [Association(Storage = "_Orders", OtherKey = "CustomerID")] public EntitySet<Order> Orders { get { return this._Orders; } set { this._Orders.Assign(value); } }
}

Notice that you do not set the value of the _Orders object, but rather call its Assign method to create the proper assignment. The EntitySet type is used because from Customers to Orders, rows are related one-tomany: one Customers row to many Orders rows.
3.

You can now access Order objects directly from the Customer objects, or vice versa. Modify the Main method with the following code to demonstrate an implicit join:
static void Main(string[] args) { // Use a standard connection string DataContext db = new DataContext(@"Data Source=.\sqlexpress;Initial Catalog=Northwind"); // Get a typed table to run queries Table<Customer> Customers = db.GetTable<Customer>(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; // Query for customers who have placed orders var custs = from c in Customers where c.Orders.Any() select c; foreach (var cust in custs) { Console.WriteLine("ID={0}, Qty={1}", cust.CustomerID, cust.Orders.Count); }

4.

Press F5 to debug the solution

Page 9

Task 3 Strongly Typing the DataContext Object


1.

Add the following code above the Customer class declaration:


public class NorthwindDataContext : DataContext { // Table<T> abstracts database details per table/date type public Table<Customer> Customers; public Table<Order> Orders; } public NorthwindDataContext(string connection) : base(connection) { }

2.

Make the following changes to the Main method to use the strongly-typed DataContext.
static void Main(string[] args) { // Use a standard connection string NorthwindDataContext db = new NorthwindDataContext(@"Data Source=.\sqlexpress;Initial Catalog=Northwind"); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; // Query for customers from London var custs = from c in db.Customers where c.City == "London" select c; foreach (var cust in custs) { Console.WriteLine("ID={0}, Qty={1}", cust.CustomerID, cust.Orders.Count); } }

3.

Press F5 to debug the solution

This optional feature is convenient since calls to GetTable<T> are not needed. Strongly typed tables can be used in all queries once such a DataContext-derived class is used.

Exercise 3 Using Code Generation to Create the Object Model


Generating the database table relationships can be a tedious and error-prone process. In this exercise well recreate the object model of the previous exercise using the new LINQ designer Task 1 - Adding a LINQ to SQL Classes file
1.

First, to clean up, delete all the classes in Program.cs weve defined, keeping only the Program class. In Microsoft Visual Studio, click the Project | Add New Item menu command In the Templates click Linq to SQL Classes

2. 3.

Page 10

4. 5.

Provide a name for the new item by entering Northwind in the Name field Click OK

Task 2 Create your object model


1. 2. 3. 4. 5.

In Server Explorer, expand Data Connections. Open the Northwind server (NORTHWND.MDF if you are using SQL Server Express). Open the Northwind.dbml file double clicking it from the solution explorer From the Tables folder drag the Customers table onto the designer surface From the Tables folder drag the Orders table onto the designer surface

Page 11

6.

Make the following changes to the Main method to use the model created by the designer.

static void Main(string[] args) { // If we query the db just designed we dont need a connection string NorthwindDataContext db = new NorthwindDataContext(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; // Query for customers from London var custs = from c in db.Customers where c.City == "London" select c; foreach (var cust in custs) { Console.WriteLine("ID={0}, Qty={1}", cust.CustomerID, cust.Orders.Count); } } Console.ReadLine();

Task 3 Querying your object model


1.

Press F5 to debug the project

Page 12

As you can see the designer has written all the plumbing code for you. You can find it in the Northwind.designer.cs file.

Task 4 Mapping a stored procedure Weve seen how to map tables to objects and how to represent relationships between tables. Now we are going to see how we can map a stored procedure to our object model.
1. 2. 3. 4.

In Server Explorer, expand Data Connections. Open the Northwind server (NORTHWND.MDF if you are using SQL Server Express). Open the Northwind.dbml file double clicking it from the solution explorer From the Stored Procedures folder drag the Ten Most Expensive Products into the method pane on the right Make the following changes to the Main method to use the method created by the designer.

5.

static void Main(string[] args) { // If we query the db just designed we dont need a connection string NorthwindDataContext db = new NorthwindDataContext(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; // Query for customers from London var custs = from c in db.Customers where c.City == "London" select c; var p10 = db.Ten_Most_Expensive_Products(); foreach (var p in p10) { Console.WriteLine("Product Name={0}, UnitPrice={1}", p.TenMostExpensiveProducts, p.UnitPrice); } Console.ReadLine(); }
6.

Press F5 to debug the project

As you type the code in, notice how, in the IDE, IntelliSense is able to show the mapped stored procedure Ten_Most_Expensive_Products as a method of the strongly typed DataContext the designer has generated. Notice also that the designer has created a Ten_Most_Expensive_Product type containing two typed properties that map to the fields returned by the stored procedure.
Generating the database table relationships can be tedious and prone to error. Until Visual Studio was extended to support LINQ, there were a code generation tool, SQLMetal, you can use to create your object model manually. The final result is the same, but you need to explicit execute external code. The easiest and better option is to use the new designer completely integrated with Visual Studio. Code generation is strictly an option you can always write your own classes or use a different code generator if you prefer. Page 13

Task 5 Retrieving new results So far we have run queries that retrieve entire objects. But you can also select the properties of interest. It is also possible to create composite results, as in traditional SQL, where an arbitrary collection of columns can be returned as a result set. In LINQ to SQL, this is accomplished through the use of anonymous types.
1.

Modify the code in the Main method as shown to create a query that only retrieves the ContactName property:
static void Main(string[] args) { // If we query the db just designed we dont need a connection string NorthwindDataContext db = new NorthwindDataContext(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; var q = from c in db.Customers where c.Region == null select c.ContactName; foreach (var c in q) Console.WriteLine(c); Console.ReadLine(); }

2.

Modify the code as shown to create a new object type to return the desired information:
static void Main(string[] args) { // If we query the db just designed we dont need a connection string NorthwindDataContext db = new NorthwindDataContext(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; var q = from c in db.Customers where c.Region == null select new { Company = c.CompanyName, Contact = c.ContactName }; foreach (var c in q) Console.WriteLine("{0}/{1}", c.Contact, c.Company); Console.ReadLine(); }

3.

Press F5 to debug the application

Notice that the new operator is invoked with no corresponding type name. This causes the compiler to create a new anonymous type based on the names and types of the selected columns. Also notice that its members are named Contact and Company. Specifying explicit names is optional, the default behavior is to

Page 14

map members based on the source field name. Finally, notice how in the foreach statement, an instance of the new type is referenced and its properties are accessed.

Add the Employees table to our object model:


1. 2. 3. 4. 5.

In Server Explorer, expand Data Connections. Open the Northwind server (NORTHWND.MDF if you are using SQL Server Express). Open the Northwind.dbml file double clicking it from the solution explorer From the Tables folder drag the Employees table onto the designer surface Change the code as follows to do a join:
static void Main(string[] args) { // If we query the db just designed we dont need a connection string NorthwindDataContext db = new NorthwindDataContext(); // Attach the log showing generated SQL to console // This is only for debugging / understanding the working of LINQ to SQL db.Log = Console.Out; var ids = ( from c in db.Customers join e in db.Employees on c.City equals e.City select e.EmployeeID) .Distinct(); foreach (var id in ids) { Console.WriteLine(id); } } Console.ReadLine();

6.

Press F5 to debug the solution

The above example illustrates how a SQL style join can be used when there is no explicit relationship to navigate. It also shows how a specific property can be selected (projection) instead of the entire object. It also shows how the query expression syntax can be blended with the Standard Query Operators Distinct() in this case.

Exercise 4 Modifying Database Data


In this exercise, you will move beyond data retrieval and see how to manipulate the data. The four basic data operations are Create, Retrieve, Update, and Delete, collectively referred to as CRUD. You will see how LINQ to SQL makes CRUD operations simple and intuitive. Task 1 Modifying your object model We are going to modify our object model by adding two more tables: 1. In Server Explorer, expand Data Connections.
2.

Open the Northwind server (NORTHWND.MDF if you are using SQL Server Express).
Page 15

3. 4. 5.

Open the Northwind.dbml file double clicking it from the solution explorer From the Tables folder drag the Order Details table onto the designer surface From the Tables folder drag the Products table onto the designer surface

Task 2 Creating a new Entity


1.

Creating a new entity is straightforward. Objects such as Customer and Order can be created with the new operator as with regular C# Objects. Of course you will need to make sure that foreign key validations succeed. Change the Main method entering the following code to create a new customer: Modify the Main method so that it appears as the following:
static void Main(string[] args) { NorthwindDataContext db = new NorthwindDataContext(); // Create the new Customer object Customer newCust = new Customer(); newCust.CompanyName = "AdventureWorks Cafe"; newCust.CustomerID = "ADVCA"; // Add the customer to the Customers table db.Customers.InsertOnSubmit(newCust); Console.WriteLine("\nCustomers matching CA before update"); var customers = db.Customers .Where(cust => cust.CustomerID.Contains("CA")); foreach (var c in customers) Console.WriteLine("{0}, {1}, {2}, {3}", c.CustomerID, c.CompanyName, c.ContactName, c.Orders.Count); Console.ReadLine(); }

2.

3.

Press F5 to debug the solution

Notice that the new row does not show up in the results. The data is not actually added to the database by this code yet.

Task 3 Updating an Entity


1.

Once you have a reference to an entity object, you can modify its properties like you would with any other object. Add the following code to modify the contact name for the first customer retrieved:
static void Main(string[] args) { NorthwindDataContext db = new NorthwindDataContext(); // Create the new Customer object Customer newCust = new Customer(); newCust.CompanyName = "AdventureWorks Cafe"; newCust.CustomerID = "ADVCA";

Page 16

// Add the customer to the Customers table db.Customers.InsertOnSubmit(newCust); Console.WriteLine("\nCustomers matching CA before update"); var customers = db.Customers .Where(cust => cust.CustomerID.Contains("CA")); foreach (var c in customers) Console.WriteLine("{0}, {1}, {2}, {3}", c.CustomerID, c.CompanyName, c.ContactName, c.Orders.Count); Customer existingCust = customers.First(); // Change the contact name of the customer existingCust.ContactName = "New Contact"; } Console.ReadLine();

As in the last task, no changes have actually been sent to the database yet.

Task 4 Deleting an Entity


1.

Using the same customer object, you can delete the first order detail. The following code demonstrates how to sever relationships between rows, and how to remove a row from the database.
static void Main(string[] args) { NorthwindDataContext db = new NorthwindDataContext(); // Create the new Customer object Customer newCust = new Customer(); newCust.CompanyName = "AdventureWorks Cafe"; newCust.CustomerID = "ADVCA"; // Add the customer to the Customers table db.Customers.InsertOnSubmit(newCust); Console.WriteLine("\nCustomers matching CA before update"); var customers = db.Customers .Where(cust => cust.CustomerID.Contains("CA")); foreach (var c in customers) Console.WriteLine("{0}, {1}, {2}, {3}", c.CustomerID, c.CompanyName, c.ContactName, c.Orders.Count); Customer existingCust = customers.First(); // Change the contact name of the customer existingCust.ContactName = "New Contact"; if (existingCust.Orders.Count > 0) { // Access the first element in the Orders collection Order ord0 = existingCust.Orders[0]; // Mark the Order row for deletion from the database db.Orders.DeleteOnSubmit(ord0); }

Page 17

Console.ReadLine();

Task 5 Submitting changes


1.

The final step required for creating, updating, and deleting objects is to actually submit the changes to the database. Without this step, the changes will only be local, will not be persisted and will not show up in query results. Insert the following code to finalize the changes:
db.SubmitChanges(); Console.ReadLine();

Dont run the program yet!


2.

Modify the main method so you can see how the code behaves before and after submitting changes to the database:
static void Main(string[] args) { NorthwindDataContext db = new NorthwindDataContext(); // Create the new Customer object Customer newCust = new Customer(); newCust.CompanyName = "AdventureWorks Cafe"; newCust.CustomerID = "ADVCA"; // Add the customer to the Customers table db.Customers.InsertOnSubmit(newCust); Console.WriteLine("\nCustomers matching CA before update"); var customers = db.Customers .Where(cust => cust.CustomerID.Contains("CA")); foreach (var c in customers) Console.WriteLine("{0}, {1}, {2}, {3}", c.CustomerID, c.CompanyName, c.ContactName, c.Orders.Count); Customer existingCust = customers.First(); // Change the contact name of the customer existingCust.ContactName = "New Contact"; if (existingCust.Orders.Count > 0) { // Access the first element in the Orders collection Order ord0 = existingCust.Orders[0]; // Mark the Order row for deletion from the database db.Orders.DeleteOnSubmit(ord0); } db.SubmitChanges(); Console.WriteLine("\nCustomers matching CA after update"); foreach (var c in db.Customers .Where(cust => cust.CustomerID.Contains("CA"))) Page 18

Console.WriteLine("{0}, {1}, {2}, {3}", c.CustomerID, c.CompanyName, c.ContactName, c.Orders.Count); Console.ReadLine(); }


3.

Press F5 to debug the solution

Naturally, once the new customer has been inserted, it cannot be inserted again due to the primary key uniqueness constraint. Therefore this program can only be run once.

Task 6 Using Transactions


1. 2.

In the Solution Explorer, right-click References, then click Add Reference In the .NET tab, click System.Transactions, then click OK By default LINQ to SQL uses implicit transactions for insert/update/delete operations. When SubmitChanges() is called, it generates SQL commands for insert/update/delete and wraps them in a transaction. But it is also possible to define explicit transaction boundaries using the TransactionScope the .NET Framework 2.0 provides. In this way, multiple queries and calls to SubmitChanges() can share a single transaction. The TransactionScope type is found in the System.Transactions namespace, and operates as it does with standard ADO.NET.

3.

At the top of Program.cs, add the following using directive:


using System.Transactions;

4.

In Main, replace the existing code with the following code to have the query and the update performed in a single transaction:
static void Main(string[] args) { NorthwindDataContext db = new NorthwindDataContext(); using (TransactionScope ts = new TransactionScope()) { var q = from p in db.Products where p.ProductID == 15 select p; Product prod = q.First(); // Show UnitsInStock before update Console.WriteLine("In stock before update: {0}", prod.UnitsInStock); if (prod.UnitsInStock > 0) prod.UnitsInStock--; db.SubmitChanges(); ts.Complete(); } Console.WriteLine("Transaction successful");

Console.ReadLine();

Page 19

}
5.

Press F5 to debug the application

Page 20

Lab Summary
Instructor's Note: LINQ to SQL is still an early technology that is evolving, but sufficient progress has been made to demonstrate powerful data capabilities. In this lab you performed the following exercises: Exercise 1 Creating your first LINQ to SQL application Exercise 2 Creating an object model from a database Exercise 3 Using code generation to create the object model Exercise 4 Modifying database data

In this lab, you learned about how the LINQ Project is advancing query capabilities in the .NET Framework. You mapped database tables to .NET classes and populated objects with live data. You also saw how seamlessly data can be retrieved and updated. Finally, you saw how richer capabilities such as transactions, custom queries, and object identity can make it easier for developers to simply concentrate on the application logic. LINQ to SQL provides a powerful bridge from objects to relational data and makes data-driven applications easier to build than ever. Thank you for trying LINQ to SQL. We hope you enjoy using LINQ in Visual Studio 2008.

Page 21

You might also like