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

ASP.NET 4 Unleased - p 102 ppsx

10 212 0

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

THÔNG TIN TÀI LIỆU

Nội dung

ptg 984 You can build LINQ to SQL query expressions dynamically by taking advantage of the System.Linq.Expressions.Expression class. This class contains all the methods for build- ing query expressions dynamically. Here is a (very partial) list of methods supported by this class: . Add()—Creates an expression that represents addition. . And()—Creates an expression that represents a logical AND. . Condition()—Creates an expression that represents a condition. . Constant()—Creates an expression that represents a constant value. . Convert()—Creates an expression that represents a conversion from one type to another. . Divide()—Creates an expression that represents division. . Equal()—Creates an expression that represents whether two expressions are equal. . Field()—Creates an expression that represents a field. . Lambda()—Creates a lambda expression. . Multiply()—Creates an expression that represents multiplication. . Or()—Creates an expression that represents a logical OR. . Parameter()—Creates an expression that represents a function parameter. . Property()—Creates an expression that represents accessing a property. . PropertyOrField()—Creates an expression that represents accessing a property or field. . Subtract()—Creates an expression that represents subtraction. Again, this is not a complete list of methods supported by the Expression class. However, it should give you some idea of how you can go about building expressions. Let’s discuss a real-world situation in which you need dynamic LINQ to SQL expressions: sorting. If you want to enable sorting when using a GridView control with LINQ to SQL, you have a choice. You can create a switch (SELECT CASE) block to sort by every possible column that a user can click, or you can create a dynamic LINQ to SQL expression. The class in Listing 20.29 contains a method called GetDynamicSort() that returns a dynamic lambda expression that can be used with either the OrderBy() or OrderByDescending()method. LISTING 20.29 Standard\App_Code\Movie.cs using System; using System.Web; using System.Collections.Generic; using System.Linq; CHAPTER 20 Data Access with LINQ to SQL From the Library of Wow! eBook ptg 985 Performing Standard Database Commands with LINQ to SQL 20 using System.Linq.Expressions; using System.Data.Linq; using System.Reflection; public partial class Movie { public static IEnumerable<Movie> Select(string orderBy) { string orderByColumn = “Id”; string orderByDirection = “asc”; if (!String.IsNullOrEmpty(orderBy)) ParseOrderBy(orderBy, ref orderByColumn, ref orderByDirection); MyDatabaseDataContext db = new MyDatabaseDataContext(); if (orderByDirection == “asc”) return db.Movies.OrderBy(GetDynamicSort(orderByColumn)); else return db.Movies.OrderByDescending(GetDynamicSort(orderByColumn)); } public static void ParseOrderBy ( string orderBy, ref string orderByColumn, ref string orderByDirection ) { string[] orderByParts = orderBy.Split(‘ ‘); orderByColumn = orderByParts[0]; if (orderByParts.Length > 1) orderByDirection = orderByParts[1].ToLower(); } private static Expression<Func<Movie, string>> GetDynamicSort ( string orderByColumn ) { // Create expression to represent Movie parameter into lambda expression ParameterExpression pMovie = Expression.Parameter(typeof(Movie), “m”); From the Library of Wow! eBook ptg 986 // Create expression to access value of order by column PropertyInfo propInfo = typeof(Movie).GetProperty(orderByColumn); MemberExpression m = Expression.MakeMemberAccess(pMovie, propInfo); // Box it UnaryExpression b = Expression.TypeAs(m, typeof(object)); // Convert to string MethodInfo convertMethod = typeof(Convert).GetMethod(“ToString”, new Type[] { typeof(object) }); MethodCallExpression c = Expression.Call(null, convertMethod, b); // Return lambda return Expression.Lambda<Func<Movie, string>>(c, pMovie); } } The GetDynamicSort() method builds a lambda expression dynamically and creates an expression that looks like this: m => Convert.ToString(m.Id As Object) When the LINQ to SQL query gets translated to SQL, the following SQL command is executed: SELECT [t0].[Id], [t0].[CategoryId], [t0].[Title], [t0].[Director], [t0].[DateReleased], [t0].[InTheaters], [t0].[BoxOfficeTotals], [t0].[Description], [t0].[Version] FROM [dbo].[Movie] AS [t0] ORDER BY CONVERT(NVarChar(MAX),[t0].[Title]) You can use the class in Listing 20.29 with the ASP.NET page in Listing 20.30. When you click a header column in GridView, it is sorted by the column. LISTING 20.30 Standard\ShowDynamicSort.aspx <%@ Page Language=”C#” trace=”true” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml”> <head runat=”server”> <title>Show Dynamic Sort</title> </head> <body> <form id=”form1” runat=”server”> <div> CHAPTER 20 Data Access with LINQ to SQL From the Library of Wow! eBook ptg 987 Performing Standard Database Commands with LINQ to SQL 20 <asp:GridView id=”grdMovies” DataSourceId=”srcMovies” AllowSorting=”true” Runat=”server” /> <asp:ObjectDataSource id=”srcMovies” TypeName=”Movie” SelectMethod=”Select” SortParameterName=”orderBy” Runat=”server” /> </div> </form> </body> </html> The GridView control has its AllowSorting attribute set to the value true and the ObjectDataSource control has its SortParameterName attribute set to the value orderBy. The page is set up to enable data source paging. NOTE The GetDynamicSort() method described in this section does a sort after converting the values of a column to strings. For nonstring data types such as dates and integers, doing string sorts produces the wrong results. For example, after sorting, the id column is ordered as 10, 2, 22, 29, 3, 30, 31, and so on. In the final part of this chapter, you learn how to create a custom entity base class that implements a more sophisticated version of a dynamic sort that sorts different column types correctly. Debugging LINQ to SQL For the sake of performance, you had better know what is going on beneath the covers when you execute LINQ to SQL queries. In particular, it is useful to know how your LINQ to SQL queries get translated into SQL and when your LINQ to SQL queries execute. In this section, I describe three methods of debugging LINQ to SQL. From the Library of Wow! eBook ptg 988 Using the LINQ to SQL Debug Visualizer The LINQ to SQL Debug Visualizer is a useful tool for viewing how a LINQ to SQL query translates into SQL. The LINQ to SQL Debug Visualizer is not included with .NET Framework. You need to download it from the following address: http://www.scottgu.com/ blogposts/linqquery/SqlServerQueryVisualizer.zip. After you download the LINQ to SQL Visualizer, you can use it like other Visualizers in Visual Web Developer and Visual Studio by compiling it and placing the resulting DLL in the My Documents\Visual Studio 2010\Visualizers folder. Then, If you set a breakpoint after a LINQ to SQL query and hover your mouse over the query, you can click the magni- fying glass to see the full SQL command into which the query gets translated (see Figure 20.1). You also have the option of executing the SQL query directly from the Visualizer. CHAPTER 20 Data Access with LINQ to SQL FIGURE 20.1 Using the LINQ to SQL Debug Visualizer. Logging LINQ to SQL Queries My favorite method of debugging LINQ to SQL queries is to log all the DataContext output to ASP.NET trace. That way, I can see all the LINQ to SQL queries that execute at the bottom of each of my ASP.NET pages (see Figure 20.2). The DataContext class includes a Log property. You can assign a TextWriter to the Log property, and DataContext writes to this TextWriter whenever it executes a query. Unfortunately, the .NET Framework does not include a TextWriter that writes to ASP.NET Trace. Fortunately, it is not that difficult to write one, and I’ve included the code for a Trace TextWriter in Listing 20.31. From the Library of Wow! eBook ptg 989 Performing Standard Database Commands with LINQ to SQL 20 LISTING 20.31 Standard\TraceWriter.cs using System; using System.Text; using System.Web; using System.IO; using System.Globalization; public class TraceWriter : TextWriter { public override void Write(string value) { HttpContext.Current.Trace.Warn(value); } public override void Write(char[] buffer, int index, int count) { HttpContext.Current.Trace.Warn(“Linq”, new string(buffer, index, count)); } public override Encoding Encoding { FIGURE 20.2 Logging LINQ to Trace. From the Library of Wow! eBook ptg 990 get { return Encoding.Unicode; } } public TraceWriter() : base(CultureInfo.CurrentCulture) { } } After you drop the class in Listing 20.31 in your App_Code folder, you can set the DataContext class to write to the TraceWriter like this: MyDatabaseDataContext db = new MyDatabaseDataContext(); db.Log = new TraceWriter(); grd.DataSource = db.Movies.Where(m=>m.Id==2); grd.DataBind(); After you set up the TraceWriter, you can enable Trace (by adding the Trace=”true” attribute to the <%@ Page %> directive) on any page that uses a LINQ query and view the output. NOTE The LINQ entity base class we create in the last part of this chapter automatically logs all output to the TraceWriter. Using the GetCommand Method Finally, you can use the DataContext.GetCommand() method to get the ADO.NET command object that executes when a LINQ to SQL query executes. After you grab the command object, you can examine its parameters or its command text. The following code assigns the command text of a command associated with a LINQ to SQL query to a Label control: MyDatabaseDataContext db = new MyDatabaseDataContext(); var query = db.Movies.Where(m=>m.Id==2); lblQuery.Text = db.GetCommand(query).CommandText; The following SELECT command is displayed in the Label control: SELECT [t0].[Id], [t0].[CategoryId], [t0].[Title], [t0].[Director], [t0].[DateReleased], [t0].[InTheaters], [t0].[BoxOfficeTotals], [t0].[Description], [t0].[Version] FROM [dbo].[Movie] AS [t0] WHERE [t0].[Id] = @p0 CHAPTER 20 Data Access with LINQ to SQL From the Library of Wow! eBook ptg 991 Creating a Custom LINQ Entity Base Class 20 Creating a Custom LINQ Entity Base Class In this final part of this chapter, we build a custom LINQ to SQL base class. Our base class contains standard methods for selecting records, inserting records, updating records, and deleting records. It also supports paging and caching. Finally, our base class contains methods for performing validation. The files for the custom classes can be found on the website that accompanies this book in the folder EntityBaseClasses. This folder contains the following files: . EntityBase—A custom base class for LINQ to SQL entities. . EntityDataSource—A custom data source control derived from the ObjectDataSource control for representing LINQ to SQL entities. . EntityValidator—A custom validation control. . EntityCallOutValidator—A custom validation control that displays a call-out vali- dation error message. . ValidationError—A class that represents a validation error. . ValidationErrorCollection—A collection of validation errors. . ValidationException—An exception thrown when there is a validation error. . TraceWriter—A class for logging LINQ to SQL queries to ASP.NET trace. The motivation for writing these classes was to make standard database operations easier when using LINQ to SQL. I discovered that I was writing the exact same queries and commands over and over again whenever I created a new entity. Writing a standard base class made my life easier because it freed me from writing the same repetitive code. Using the Entity Base Class Follow these steps to use the custom entity base classes: 1. Create a new website. 2. Add an App_Code folder to your website, and copy the EntityBaseClasses folder to the App_Code folder. 3. Create one or more LINQ to SQL entities with the help of the LINQ to SQL Designer. 4. Add a connection string named con to your database in the web.config file. 5. Create a separate partial class for each LINQ to SQL entity and derive the class from the EntityBase class. 6. Create an empty Validate() method for each entity class. For example, imagine that you have used the LINQ to SQL Designer to create an entity named Movie. You created the Movie entity by dragging the Movie database table from the Database Explorer (Server Explorer) window onto the LINQ to SQL Designer surface. At this point, you are ready to inherit your new Movie entity from the EntityBase class. From the Library of Wow! eBook ptg 992 Listing 20.32 contains the file that you add to your website to create a Movie entity that inherits from the EntityBase class. LISTING 20.32 ShowEntityBase\App_Code\Movie.cs using System; public partial class Movie : EntityBase<Movie> { protected override void Validate() { } } Now that you have derived the Movie entity from EntityBase, the Movie class inherits methods for selecting, inserting, updating, and deleting records. Performing Standard Data-Access Operations with the EntityBase Class Any entity that you inherit from the EntityBase class inherits the following methods automatically: . Select()—Selects all entities. . Select(string orderBy)—Selects all entities in a certain order. . SelectCached()—Selects all entities from the cache. . SelectCached(string orderBy)—Selects all entities from the cache in a certain order. . Select(int startRowIndex, int maximumRows)—Selects a page of entities. . Select(int startRowIndex, int maximumRows, orderBy)—Selects a page of entities in a certain order. . SelectCount()—Returns a count of entities. . SelectCount(string orderBy)—Returns a count of entities. . SelectCountCached()—Returns a count of entities from the cache. . Get(int? Id)—Gets a single entity using the entity’s identity value. . Save(T oldEntity, T newEntity)—Either performs an insert or update depending on whether the identity value is 0. . Insert(T entityToInsert)—Inserts a new entity. . Update(T oldEntity, T newEntity)—Updates an existing entity. . Delete(T entityToDelete)—Deletes an entity. CHAPTER 20 Data Access with LINQ to SQL From the Library of Wow! eBook ptg 993 Creating a Custom LINQ Entity Base Class 20 Two of these methods—Get() and Save()—require that the database table an entity repre- sents include an identity column. The other methods do not make this assumption. The page in Listing 20.33 illustrates how you can use these methods. LISTING 20.33 ShowEntityBase\SelectPagedSortedMovies.aspx <%@ Page Language=”C#” Trace=”true” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml”> <head id=”Head1” runat=”server”> <title>Select Paged Sorted Movies</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:GridView id=”grdMovies” DataSourceId=”srcMovies” AllowPaging=”true” AllowSorting=”true” Runat=”server” /> <asp:ObjectDataSource id=”srcMovies” TypeName=”Movie” SelectMethod=”Select” EnablePaging=”true” SelectCountMethod=”SelectCountCached” SortParameterName=”orderBy” Runat=”Server” /> </div> </form> </body> </html> The page in Listing 20.33 contains a GridView control bound to an ObjectDataSource control. The ObjectDataSource control represents the Movie entity. The ObjectDataSource is configured to support data source paging and sorting. You get both the Select() and SelectCountCached() methods for free from the EntityBase class. The EntityBaseClasses folder also contains a control named EntityDataSource, which can be used instead of the normal ObjectDataSource. The EntityDataSource control inherits From the Library of Wow! eBook . PropertyInfo propInfo = typeof(Movie).GetProperty(orderByColumn); MemberExpression m = Expression.MakeMemberAccess(pMovie, propInfo); // Box it UnaryExpression b = Expression.TypeAs(m, typeof(object)); //. represents a function parameter. . Property()—Creates an expression that represents accessing a property. . PropertyOrField()—Creates an expression that represents accessing a property or field. expression to represent Movie parameter into lambda expression ParameterExpression pMovie = Expression.Parameter(typeof(Movie), “m”); From the Library of Wow! eBook ptg 986 // Create expression to

Ngày đăng: 06/07/2014, 18:20

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN