1. Trang chủ
  2. » Công Nghệ Thông Tin

Apress pro LINQ Language Integrated Query in C# 2008 phần 9 ppt

68 349 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 68
Dung lượng 1,13 MB

Nội dung

436 CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS Notice that in the join statement in Listing 14-14, I direct the join results into the temporary sequence named temp. That temporary sequence name can be whatever you want, as long as it doesn’t conflict with any other name or keyword. Then I perform a subsequent query on the results of the temp sequence passed to the DefaultIfEmpty operator. Even though I haven’t covered it yet, the DefaultIfEmpty operator called in Listing 14-14 is not the same operator that was discussed in Chapter 4. As I will explain shortly, LINQ to SQL queries are translated into SQL statements, and those SQL statements are executed by the database. SQL Server has no way to call the DefaultIfEmpty standard query operator. Instead, that operator call will be translated into the appropriate SQL state- ment. This is why I wanted the DataContext logging to be enabled. Also, notice that I access the city name from the Suppliers table instead of the temp collection. I did this because I know there will always be a record for the supplier, but for suppliers without a matching customer, there will be no city in the joined results in the temp collection. This is different than the previous example of the inner join where I obtained the city from the joined table. In that example, it didn’t matter which of the tables I got the city from, because if a matching customer record didn’t exist, there would be no record anyway since an inner join was performed. Let’s look at the results of Listing 14-14. SELECT [t0].[CompanyName], [t1].[CompanyName] AS [value], [t0].[City] FROM [dbo].[Suppliers] AS [t0] LEFT OUTER JOIN [dbo].[Customers] AS [t1] ON [t0].[City] = [t1].[City] Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1 London: Exotic Liquids - Around the Horn London: Exotic Liquids - B's Beverages London: Exotic Liquids - Consolidated Holdings London: Exotic Liquids - Eastern Connection London: Exotic Liquids - North/South London: Exotic Liquids - Seven Seas Imports New Orleans: New Orleans Cajun Delights - Ann Arbor: Grandma Kelly's Homestead - Tokyo: Tokyo Traders - Oviedo: Cooperativa de Quesos 'Las Cabras' - Osaka: Mayumi's - Melbourne: Pavlova, Ltd. - Manchester: Specialty Biscuits, Ltd. - Göteborg: PB Knäckebröd AB - Sao Paulo: Refrescos Americanas LTDA - Comércio Mineiro Sao Paulo: Refrescos Americanas LTDA - Familia Arquibaldo Sao Paulo: Refrescos Americanas LTDA - Queen Cozinha Sao Paulo: Refrescos Americanas LTDA - Tradiçao Hipermercados Berlin: Heli Süßwaren GmbH & Co. KG - Alfreds Futterkiste Frankfurt: Plutzer Lebensmittelgroßmärkte AG - Cuxhaven: Nord-Ost-Fisch Handelsgesellschaft mbH - Ravenna: Formaggi Fortini s.r.l. - Sandvika: Norske Meierier - Bend: Bigfoot Breweries - Stockholm: Svensk Sjöföda AB - Paris: Aux joyeux ecclésiastiques - Paris spécialités Paris: Aux joyeux ecclésiastiques - Spécialités du monde Boston: New England Seafood Cannery - Singapore: Leka Trading - Lyngby: Lyngbysild - Rattz_789-3C14.fm Page 436 Tuesday, October 16, 2007 1:27 PM CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS 437 Zaandam: Zaanse Snoepfabriek - Lappeenranta: Karkki Oy - Sydney: G'day, Mate - Montréal: Ma Maison - Mère Paillarde Salerno: Pasta Buttini s.r.l. - Montceau: Escargots Nouveaux - Annecy: Gai pâturage - Ste-Hyacinthe: Forêts d'érables - As you can see in the output of Listing 14-14, I got at least one record for every supplier, and you can see that some suppliers do not have a matching customer, thereby proving the outer join was performed. But, if there is any doubt, you can see the actual generated SQL statement and that clearly is performing an outer join. To Flatten or Not to Flatten In the examples in Listing 14-13 and Listing 14-14, I projected my query results into a flat structure. By this, I mean an object was created from an anonymous class where each field requested is a member of that anonymous class. Contrast this with the fact that, instead of creating a single anon- ymous class containing each field I wanted, I could have created an anonymous class composed of a Supplier object and matching Customer object. In that case, there would be the topmost level of the anonymous class, and a lower level containing a Supplier object and either a Customer object or the default value provided by the DefaultIfEmpty operator, which would be null. If I take the flat approach, as I did in the two previous examples, because the projected output class is not an entity class, I will not be able to perform updates to the output objects by having the DataContext object manage persisting the changes to the database for me. This is fine for data that will not be changed. However, sometimes you may be planning on allowing updates to the retrieved data. In this case, using the nonflat approach would allow you to make changes to the retrieved objects and have the DataContext object manage the persistence. I will cover this in more depth in Chapter 16. For now, let’s just take a look at Listing 14-15, which contains an example that isn’t flat. Listing 14-15. Returning Nonflat Results so the DataContext Can Manage Persistence Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); var entities = from s in db.Suppliers join c in db.Customers on s.City equals c.City into temp from t in temp.DefaultIfEmpty() select new { s, t }; foreach (var e in entities) { Console.WriteLine("{0}: {1} - {2}", e.s.City, e.s.CompanyName, e.t != null ? e.t.CompanyName : ""); } In Listing 14-15, instead of returning the query results into a flat anonymous object with a member for each desired field, I return the query results in an anonymous object composed of the Supplier and potentially Customer entity objects. Also notice that in the Console.WriteLine method call, I still have to be concerned that the temporary result can be a null if no matching Customer object exists. Let’s take a look at the results of Listing 14-15. Rattz_789-3C14.fm Page 437 Tuesday, October 16, 2007 1:27 PM 438 CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS London: Exotic Liquids - Around the Horn London: Exotic Liquids - B's Beverages London: Exotic Liquids - Consolidated Holdings London: Exotic Liquids - Eastern Connection London: Exotic Liquids - North/South London: Exotic Liquids - Seven Seas Imports New Orleans: New Orleans Cajun Delights - Ann Arbor: Grandma Kelly's Homestead - Tokyo: Tokyo Traders - Oviedo: Cooperativa de Quesos 'Las Cabras' - Osaka: Mayumi's - Melbourne: Pavlova, Ltd. - Manchester: Specialty Biscuits, Ltd. - Göteborg: PB Knäckebröd AB - Sao Paulo: Refrescos Americanas LTDA - Comércio Mineiro Sao Paulo: Refrescos Americanas LTDA - Familia Arquibaldo Sao Paulo: Refrescos Americanas LTDA - Queen Cozinha Sao Paulo: Refrescos Americanas LTDA - Tradiçao Hipermercados Berlin: Heli Süßwaren GmbH & Co. KG - Alfreds Futterkiste Frankfurt: Plutzer Lebensmittelgroßmärkte AG - Cuxhaven: Nord-Ost-Fisch Handelsgesellschaft mbH - Ravenna: Formaggi Fortini s.r.l. - Sandvika: Norske Meierier - Bend: Bigfoot Breweries - Stockholm: Svensk Sjöföda AB - Paris: Aux joyeux ecclésiastiques - Paris spécialités Paris: Aux joyeux ecclésiastiques - Spécialités du monde Boston: New England Seafood Cannery - Singapore: Leka Trading - Lyngby: Lyngbysild - Zaandam: Zaanse Snoepfabriek - Lappeenranta: Karkki Oy - Sydney: G'day, Mate - Montréal: Ma Maison - Mère Paillarde Salerno: Pasta Buttini s.r.l. - Montceau: Escargots Nouveaux - Annecy: Gai pâturage - Ste-Hyacinthe: Forêts d'érables – In the output for Listing 14-15, you can see that some suppliers do not have customers in their cities. Unlike the sequence of anonymous objects returned by the query in Listing 14-14, the anony- mous objects returned by the query in Listing 14-15 contain entity objects of type Supplier and Customer. Because these are entity objects, I can take advantage of the services provided by the DataContext to manage the changes to them, and their persistence to the database. Deferred Query Execution I know by now you have probably read my explanation of deferred query execution a dozen times. But, being neurotic, I am always paranoid that you may have skipped some pertinent part of a previous chapter. In this case, I am concerned you might have missed the explanation of deferred query execution. Deferred query execution refers to the fact that a LINQ query of any type—be it a LINQ to SQL query, a LINQ to XML query, or a LINQ to Objects query—may not actually be executed at the time it is defined. Take the following query, for example: Rattz_789-3C14.fm Page 438 Tuesday, October 16, 2007 1:27 PM CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS 439 IQueryable<Customer> custs = from c in db.Customers where c.Country == "UK" select c; The database query is not actually performed when this statement is executed; it is merely defined and assigned to the variable custs. The query will not be performed until the custs sequence is enumerated. This has several repercussions. Repercussions of Deferred Query Execution One repercussion of deferred query execution is that your query can contain errors that will cause exceptions but only when the query is actually performed, not when defined. This can be very misleading when you step over the query in the debugger and all is well, but then, farther down in the code, an exception is thrown when enumerating the query sequence. Or, perhaps you call another operator on the query sequence that results in the query sequence being enumerated. Another repercussion is that, since the SQL query is performed when the query sequence is enumerated, enumerating it multiple times results in the SQL query being performed multiple times. This could certainly hamper performance. The way to prevent this is by calling one of the standard query operator conversion operators, ToArray<T>, ToList<T>, ToDictionary<T, K>, or ToLookup<T, K>, on a sequence. Each of these operators will convert the sequence on which it is called to a data struc- ture of the type specified, which in effect, caches the results for you. You can then enumerate that new data structure repeatedly without causing the SQL query to be performed again and the results potentially changing. Taking Advantage of Deferred Query Execution One advantage of deferred query execution is that performance can be improved while at the same time allowing you to reuse previously defined queries. Since the query is executed every time the query sequence is enumerated, you can define it once and enumerate it over and over, whenever the situation warrants. And, if the code flow takes some path that doesn’t need to actually examine the query results by enumerating them, performance is improved because the query is never actually executed. Another of the benefits of deferred query execution is that, since the query isn’t actually performed by merely defining it, we can append additional operators programmatically as needed. Imagine an application that allows the user to query customers. Also imagine that the user can filter the queried customers. Picture one of those filter-type interfaces that have a drop-down list for each column in the customer table. There is a drop-down list for the City column and another for the Country column. Each drop-down list has every city and country from all Customer records in the database. At the top of each drop-down list is an [ALL] option, which is the default for its respective database column. If the user hasn’t changed the setting of either of those drop-down lists, no additional where clause is appended to the query for the respective column. Listing 14-16 contains an example programmati- cally building a query for such an interface. Listing 14-16. Programmatically Building a Query Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); // Turn on the logging. db.Log = Console.Out; // Pretend the values below are not hardcoded, but instead, obtained by accessing // a dropdown list's selected value. string dropdownListCityValue = "Cowes"; Rattz_789-3C14.fm Page 439 Tuesday, October 16, 2007 1:27 PM 440 CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS string dropdownListCountryValue = "UK"; IQueryable<Customer> custs = (from c in db.Customers select c); if (!dropdownListCityValue.Equals("[ALL]")) { custs = from c in custs where c.City == dropdownListCityValue select c; } if (!dropdownListCountryValue.Equals("[ALL]")) { custs = from c in custs where c.Country == dropdownListCountryValue select c; } foreach (Customer cust in custs) { Console.WriteLine("{0} - {1} - {2}", cust.CompanyName, cust.City, cust.Country); } In Listing 14-16, I simulate obtaining the user selected city and country from their drop-down lists, and only if they are not set to "[ALL]", I append an additional where operator to the query. Because the query is not actually performed until the sequence is enumerated, I can programmatically build it, a portion at a time. Let’s take a look at the results of Listing 14-16. SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE ([t0].[Country] = @p0) AND ([t0].[City] = @p1) @p0: Input String (Size = 2; Prec = 0; Scale = 0) [UK] @p1: Input String (Size = 5; Prec = 0; Scale = 0) [Cowes] Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1 Island Trading - Cowes - UK Notice that since I specified that the selected city was Cowes and the selected country was UK, I got the records for the customers in Cowes in the United Kingdom. Also notice that there is a single SQL statement that was performed. Because the query’s execution is deferred until it is actually needed, I can continue to append to the query to further restrict it, or perhaps order it, without the expense of multiple SQL queries taking place. You can see that both of the filter criteria, the city and country, do appear in the where clause of the executed SQL statement. For another test, in Listing 14-17, I’ll change the value of the dropdownListCityValue variable to "[ALL]" and see what the executed SQL statement looks like then and what the results are. Since the default city of "[ALL]" is specified, the SQL query shouldn’t even restrict the results set by the city. Rattz_789-3C14.fm Page 440 Tuesday, October 16, 2007 1:27 PM CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS 441 Listing 14-17. Programmatically Building Another Query Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); // Turn on the logging. db.Log = Console.Out; // Pretend the values below are not hardcoded, but instead, obtained by accessing // a dropdown list's selected value. string dropdownListCityValue = "[ALL]"; string dropdownListCountryValue = "UK"; IQueryable<Customer> custs = (from c in db.Customers select c); if (!dropdownListCityValue.Equals("[ALL]")) { custs = from c in custs where c.City == dropdownListCityValue select c; } if (!dropdownListCountryValue.Equals("[ALL]")) { custs = from c in custs where c.Country == dropdownListCountryValue select c; } foreach (Customer cust in custs) { Console.WriteLine("{0} - {1} - {2}", cust.CompanyName, cust.City, cust.Country); } Let’s examine the output of Listing 14-17. SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE [t0].[Country] = @p0 @p0: Input String (Size = 2; Prec = 0; Scale = 0) [UK] Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1 Around the Horn - London - UK B's Beverages - London - UK Consolidated Holdings - London - UK Eastern Connection - London - UK Island Trading - Cowes - UK North/South - London - UK Seven Seas Imports - London - UK You can see that the where clause of the SQL statement no longer specifies the city, which is exactly what I wanted. You can also see in the output results that there are now customers from different cities in the United Kingdom. Rattz_789-3C14.fm Page 441 Tuesday, October 16, 2007 1:27 PM 442 CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS Of course, you can always append a call to the ToArray<T>, ToList<T>, ToDictionary<T, K>, or ToLookup<T, K> standard query operators to force the query to execute when you want. I hope you can see that deferred query execution can be your friend. I also hope by now that you can see the usefulness of the DataContext.Log. The SQL IN Statement with the Contains Operator One of the SQL query capabilities that early incarnations of LINQ to SQL lacked was the ability to perform a SQL IN statement, such as the one in the following SQL query: A SQL Query with an IN Statement SELECT * FROM Customers WHERE (City IN ('London', 'Madrid')) To alleviate this problem, Microsoft added the Contains operator. This operator is used differ- ently, though, than may be immediately obvious. To me, it seems to work backward of the way I would expect an implementation of the SQL IN statement to work. I would expect to be able to say some member of an entity class must be IN some set of values. Instead, it works in the opposite manner. Let’s take a look at Listing 14-18 where I demonstrate the Contains operator. Listing 14-18. The Contains Operator Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); db.Log = Console.Out; string[] cities = { "London", "Madrid" }; IQueryable<Customer> custs = db.Customers.Where(c => cities.Contains(c.City)); foreach (Customer cust in custs) { Console.WriteLine("{0} - {1}", cust.CustomerID, cust.City); } As you can see in Listing 14-18, instead of writing the query so that the customer’s city must be in some set of values, you write the query so that some set of values contains the customer’s city. In the case of Listing 14-18, I create an array of cities named cities. In my query, I then call the Contains operator on the cities array and pass it the customer’s city. If the cities array contains the customer’s city, true will be returned to the Where operator and that will cause the Customer object to be included in the output sequence. Let’s take a look at the output of Listing 14-18. SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] IN (@p0, @p1) @p0: Input String (Size = 6; Prec = 0; Scale = 0) [London] @p1: Input String (Size = 6; Prec = 0; Scale = 0) [Madrid] Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1 Rattz_789-3C14.fm Page 442 Tuesday, October 16, 2007 1:27 PM CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS 443 AROUT - London BOLID - Madrid BSBEV - London CONSH - London EASTC - London FISSA - Madrid NORTS - London ROMEY - Madrid SEVES – London Looking at the generated SQL statement, you can see that the Contains operator was translated into a SQL IN statement. Updates Making database updates with LINQ to SQL is as easy as changing properties on an object, calling the DataContext object’s SubmitChanges method, and handling any concurrency conflicts that may occur. Don’t let the concurrency conflict handling intimidate you, there are several options for handling conflicts, and none of them are too painful. I will cover detecting and handling conflicts in detail in Chapter 17. Of course, this simplicity is only true if you have properly written entity classes that are mapped to the database properly and maintain graph consistency. For more information about mapping the entity classes to the database, read the section titled “Entity Class Attributes and Attribute Properties” in Chapter 15. For more information about graph consistency, read the section titled “Graph Consistency” in that same chapter. However, SQLMetal and the Object Relational Designer handle all of the necessary plumbing to make all this just happen. For a simple example of making an update to the database, you merely need to look at the first example in Chapter 12, Listing 12-1. Updating Associated Classes By design, LINQ to SQL allows you to update either side of associated classes to remove the relation- ship between them. You could update a parent object’s reference to one of its children, or you could update that child’s reference to the parent. Obviously, the references at each end of that relationship must be updated, but you only need to update one side or the other. It is not LINQ to SQL that keeps your object model’s graph consistent when updating one side; it is the responsibility of the entity class to make this happen. Please read the section titled “Graph Consistency” in Chapter 15 for more information on how this should be implemented. However, SQLMetal and the Object Relational Designer handle this for you if you allow them to create your entity classes. Updating a Child’s Parent Reference Since we can update either side of the relationship, we could choose to update a child’s parent refer- ence. So, as an example, let’s see how I would change the employee that gets credit for an order in the Northwind database by examining Listing 14-19. Because this example is more complex than many of the others, I will explain it as I go. Rattz_789-3C14.fm Page 443 Tuesday, October 16, 2007 1:27 PM 444 CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS Listing 14-19. Changing a Relationship by Assigning a New Parent Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); Order order = (from o in db.Orders where o.EmployeeID == 5 orderby o.OrderDate descending select o).First<Order>(); // Save off the current employee so I can reset it at the end. Employee origEmployee = order.Employee; In the preceding code, after obtaining the DataContext, I query for the most recent order of the employee whose EmployeeID is 5 by ordering that person’s orders by date in descending order and calling the First operator. This will provide me the most recent order. Next, just so I will have a refer- ence to the original employee this order was credited to, so that I can restore it at the end of the example, I save the reference in a variable named origEmployee. Console.WriteLine("Before changing the employee."); Console.WriteLine("OrderID = {0} : OrderDate = {1} : EmployeeID = {2}", order.OrderID, order.OrderDate, order.Employee.EmployeeID); Next, I display a line to the console letting you know I haven’t changed the employee for the retrieved order yet, followed by displaying the order’s ID, date, and credited employee to the screen. We should see that the order is credited to employee 5, since that is the employee I queried to obtain the order. Employee emp = (from e in db.Employees where e.EmployeeID == 9 select e).Single<Employee>(); // Now I will assign the new employee to the order. order.Employee = emp; db.SubmitChanges(); Next, I query for some other employee, the one whose EmployeeID is 9, that I then set to be the credited employee for the previously queried order. Then, I persist the changes by calling the SubmitChanges method. Now, to prove the change was really made at both ends, I could just show you the credited employee for the queried order, but that would be anticlimactic, since you just saw me set the Employee property of the order, and it wouldn’t really prove to you that the change was made on the employee side of the relationship. It would be much more satisfying for me to find the order I just changed in the new employee’s collection of orders, so that is what I will do. Order order2 = (from o in emp.Orders where o.OrderID == order.OrderID select o).First<Order>(); In the preceding code, I query for the order I changed by its OrderID in the new employee’s Orders. If it is found, that will prove the relationship between the employee and order was updated on both ends of the relationship. Console.WriteLine("{0}After changing the employee.", System.Environment.NewLine); Console.WriteLine("OrderID = {0} : OrderDate = {1} : EmployeeID = {2}", order2.OrderID, order2.OrderDate, order2.Employee.EmployeeID); Rattz_789-3C14.fm Page 444 Tuesday, October 16, 2007 1:27 PM CHAPTER 14 ■ LINQ TO SQL DATABASE OPERATIONS 445 In the preceding code, I merely display to the console that I am about to display the order after changing it to the new employee emp. I then display that order. We should see that its employee is the employee whose EmployeeID is 9. Prior to the change, the EmployeeID was 5. // Now I need to reverse the changes so the example can be run multiple times. order.Employee = origEmployee; db.SubmitChanges(); The last two lines of code, as well as the line that saves the order’s original employee, are merely for resetting the database so the example can be run multiple times. Now, let’s examine the output for Listing 14-19. Before changing the employee. OrderID = 11043 : OrderDate = 4/22/1998 12:00:00 AM : EmployeeID = 5 After changing the employee. OrderID = 11043 : OrderDate = 4/22/1998 12:00:00 AM : EmployeeID = 9 As you can see, the employee for the order before the change was the employee whose EmployeeID is 5. After the change of the order’s credited employee, the order’s credited EmployeeID is 9. What is significant is that I didn’t just display the order’s credited employee on the same order variable, order. I retrieved that order from the employee whose EmployeeID is 9. This proves that the order was indeed changed on the employee side of the relationship. In this example, I updated the child object’s parent reference, where the child was the order and the parent was the employee. There is yet another approach I could have taken to achieve the same result. I could have updated the parent object’s child reference. Updating a Parent’s Child Reference Another approach to changing the relationship between two objects is to remove the child object from the parent object’s EntitySet<T> collection and add it to a different parent’s EntitySet<T> collection. In Listing 14-20, I will remove the order from the employee’s collection of orders. Because this example is similar to Listing 14-19, I will be far briefer in the explanation, but the significant differences will be in bold. Listing 14-20. Changing a Relationship by Removing and Adding a Child to a Parent’s EntitySet Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); Order order = (from o in db.Orders where o.EmployeeID == 5 orderby o.OrderDate descending select o).First<Order>(); // Save off the current employee so I can reset it at the end. Employee origEmployee = order.Employee; Console.WriteLine("Before changing the employee."); Console.WriteLine("OrderID = {0} : OrderDate = {1} : EmployeeID = {2}", order.OrderID, order.OrderDate, order.Employee.EmployeeID); Employee emp = (from e in db.Employees where e.EmployeeID == 9 select e).Single<Employee>(); Rattz_789-3C14.fm Page 445 Tuesday, October 16, 2007 1:27 PM [...]... 'LONEP' select c).Single(); Notice that instead of using the C# equality operator, (==), the SQL equality operator (=) is used Instead of enclosing the string literal in double quotes (""), single quotes ('') enclose it One of the goals of LINQ is to allow developers to program in their native programming languages Remember, LINQ stands for Language Integrated Query However, since the database... created by providing an XML mapping file when instantiating the DataContext object Those attributes or mapping file entries dictate how the entity classes are to be mapped to a SQL Server database when using LINQ to SQL By using these entity classes, we can query and update the database using LINQ to SQL Creating Entity Classes Entity classes are the basic building blocks utilized when performing LINQ to... [Table(Name="dbo.Customers")] public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged { private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); public event PropertyChangingEventHandler PropertyChanging; public event PropertyChangedEventHandler PropertyChanged; } When the DataContext object initiates change tracking for an entity object, the DataContext... generates SendPropertyChanging and SendPropertyChanged methods for you From the Generated Customer Entity Class protected virtual void SendPropertyChanging() { if ((this.PropertyChanging != null)) { this.PropertyChanging(this, emptyChangingEventArgs); } } protected virtual void SendPropertyChanged(String propertyName) { if ((this.PropertyChanged != null)) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));... attempting to override these methods SQL Translation When writing LINQ to SQL queries, you may have noticed that when specifying expressions such as where clauses, the expressions are in the native programming language, as opposed to SQL After all, this is part of the goal of LINQ, language integration For this book, the expressions are in C# If you haven’t noticed, shame on you For example, in Listing... pass String.Empty to its constructor 4 59 Rattz_7 89- 3C15.fm Page 460 Tuesday, October 16, 2007 1:40 PM 460 CHAPTER 15 ■ LINQ TO S QL ENTITY C LASS ES From the Generated Customer Entity Class [Table(Name="dbo.Customers")] public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged { private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);... passed parameter is just fine This makes sense LINQ to SQL would have no problem calling the TrimEnd method on our parameter, because it can do this prior to binding the parameter to the query, which occurs in our process environment Calling the TrimEnd method on the database column would have to be done in the database, and that means, instead of calling the method in our process environment, that... System.ComponentModel.INotifyPropertyChanging and System ComponentModel.INotifyPropertyChanged As I will do often in the LINQ to SQL chapters, I will refer to the code that was generated by SQLMetal to show you the quintessential way to handle some situation In this case, I will refer to the SQLMetal-generated code to handle change notifications To implement the INotifyPropertyChanging and INotifyPropertyChanged interfaces,... property to null in the following line this._Customer.Entity = null; The Entity property is set to null in the preceding line of code to halt the recursion that will be set in motion in the next line of code Since the Order object’s Customer property’s Entity property is now null and doesn’t reference the actual Customer object, but the Customer object’s Orders property still contains this Order in its collection,... string literal In listing 14-25, I’ll reverse the side I call the TrimEnd method on, and see what happens Listing 14-25 A LINQ to SQL Query That Can Be Translated Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); IQueryable custs = from c in db.Customers where c.CustomerID == "LAZY".TrimEnd('K') select c; foreach (Customer c in custs) { Console.WriteLine("{0}", . (""), single quotes ('') enclose it. One of the goals of LINQ is to allow developers to program in their native programming languages. Remember, LINQ stands for Language Integrated Query. . deferred query execution. Deferred query execution refers to the fact that a LINQ query of any type—be it a LINQ to SQL query, a LINQ to XML query, or a LINQ to Objects query may not actually be executed. to the query for the respective column. Listing 14-16 contains an example programmati- cally building a query for such an interface. Listing 14-16. Programmatically Building a Query Northwind db

Ngày đăng: 06/08/2014, 08:22

TỪ KHÓA LIÊN QUAN