Microsoft LINQ

Total Page:16

File Type:pdf, Size:1020Kb

Microsoft LINQ

Microsoft LINQ

Ryan Wiederholt Computer Science University of Wisconsin Platteville [email protected]

Abstract

In the last few years, Microsoft has released many interesting tools to make a software developer's task quicker and easier. One of those tools is LINQ. Released in 2007, LINQ was designed to be a universal query library that would allow developers to easily retrieve data from in-memory containers, XML documents, and SQL Server databases. Across all these different data sources, the LINQ syntax would remain the same. The introduction of LINQ also brought about new data types, new interfaces, and lambda expressions. LINQ syntax borrows its style from SQL, making its syntax easy to understand for those who have experience with SQL queries. This presentation will cover the mentioned attributes of LINQ in depth, along with how to implement it.

Introduction and History

LINQ was introduced with the release of .NET Framework 3.5 on November 19, 2007. Along with this release came Visual Studio 2008, which was required in order to use the methods of LINQ. C# and Visual Basic .Net are the only languages to officially support LINQ, although unofficial implementations have been made for many other languages.[1]

Many of the features seen in LINQ were previously part of the Cω project started in 2004. The aim of the Cω project was to make certain data stores, SQL databases and XML documents in this case, accessible in a way similar to traditional types like strings and arrays. This would provide type safety for the data retrieved using the Cω methods.[2]

LINQ added to the functionality brought about by the Cω project. Along with refined SQL and XML retrieval operations, the ability to query an in memory data source was added. Now arrays, .Net container objects, even strings could be queried with LINQ. The syntax and functionality for a LINQ statement was not dependent on the source of the data. Query methods opened up new ways of retrieving data from containers. Functions like "Join" and "Group" were now not just an SQL specific feature: with LINQ, these functions could be performed on many different types of containers. Type conversion and safety when working with relational data in an object oriented environment was simplified in LINQ. All data returned from a query is assigned and converted to the proper type without any user interaction. This greatly simplified working with relational data. 2

Prerequisites for Using LINQ

LINQ makes use of some features in the .Net framework that will need to be understood in order to make the most efficient use of LINQ. These features include object initialization expressions, the var keyword, anonymous types, and lambda expressions. These features are not specific to LINQ and can be used in operations other than LINQ.

Object Initialization Expressions

Object initializers allow a developer to set an object's public fields, also referred to as properties, without having to call a constructor. The process of using an object initializer is similar to initializing the values of an array. If an object does not have a constructor, it can still be initialized using an object initialization expression. See Figure 1 for an example of object initializer use. [3]

In the class "Homework" from figure 1, auto-implemented properties are used for the data in Homework. Auto-implemented properties allow get and set methods for an object to be quickly created. However, auto-implemented properties do not perform any logic to verify values that are passed through the properties. If additional logic needs to be used, it is best to explicitly write the properties an object. var Keyword

The var keyword is used in place of an explicit data type when defining variables. When a variable is defined with var, the compiler uses the expression on the right side of the assignment statement to infer the type of the variable. The variable is still considered to be strongly typed. The compiler can infer any data type from the built in data types (int, char, etc.), anonymous types, user defined types, and types defined in a .NET Framework class library. The var keyword is demonstrated in Figure 2. [3]

Anonymous Types

Anonymous types allow a developer to create an object type on the fly without having to explicitly create a new class. When an anonymous type object is created, the complier infers the type of each property. Properties within an anonymous type are read-only. To create an anonymous type, the var keyword must be used. The var keyword will instruct the compiler to infer the variable type. Since there will be no types that match an anonymous type, the complier will create a new type on the fly for the selected data. See Figure 2 for an example of creating an anonymous type and accessing it's data.[3] 3

Lambda Expressions

Lambda expressions were added to the C# language at the same time as the LINQ release. As such, they can be quite handy when dealing with LINQ queries. A lambda expression is just a very compact way of writing a function. Figure 3 shows an example of counting integers equal to 2 in a given list by using a lambda expression.

The lambda expression in this example is used as a parameter for the function "Count". The lambda operator is "=>". On the left side of the lambda operator is one element from the object we are calling the function from, in this case integers. i will act as an iterator through the collection, performing the expression on the right side of the lambda operator on every element in the collection. The right side contains a boolean expression performed on the left side iterator and another variable/constant, in this case 2. The lambda expression above would read as "i, such that i equals 2" in plain English.

It should also be noted that there are other ways of using lambda expressions in C#. Using a lambda with a boolean expression as a filter is the way that LINQ will utilize them. [4]

LINQ Syntax

There are two different ways of writing a LINQ query. The most commonly used method resembles an SQL query in reverse. The second method is to use functions combined with lambda. Figure 4 demonstrates both methods of writing a query against a List of int.

Query1 can be broken down into three distinct sections. First is the variable assignment on the left side of the equals operator. In most cases, var is used to allow the compiler to select the type. LINQ queries are not often returned with a basic type, such as an array or even a .Net container. IEnumerable<> and IQueryable<> are the most often returned types. The first line of the right side specifies the source to query using the "from" keyword. The variable i is a single object within the data source. This variable works as an iterator for the data source when the query is executed. This variable does not have to be called i, it can be called whatever the developer chooses. The "in" keyword is always required. Finally comes the data source, which in this case is intList. The data source must be initialized before performing the query, however, an empty data source will not throw any errors. Instead, the LINQ query will return an empty data set. The 4 second line of the query is the select statement. In Figure 3, specifying i in the select statement takes all variables in intList that meet any filters (there are no filters in this query). When working with types that have more than one property, it is possible to retrieve only certain properties of the type instead of all the properties of the type.

Query2 utilizes function calls and lambda expressions to perform queries. In this case, the lambda just takes everything in intList, since there is not a boolean operation. The left side of the assignment operator functions in the same way as Query1. On the right side, the from statement of Query1 is replaced by just calling a function from the data source.

The basic format of a LINQ query can be extended to perform additional functions when getting data. Table 1 gives a list of some of the common actions that can be performed when querying. To use a function, the command and any arguments are put after the for statement but before the select statement in a query. In the case of using function calls and lambda to query, call these functions before the select statement. Most of these functions will require lambdas as a parameter. For a complete list of additional actions, visit the Microsoft LINQ MSDN webpage. [1]

Table 1: LINQ Operators

Operator Description Example Where Filter results based on var ints = from i in Intlist boolean statements where i >= 0 select i;

Join Select associated data from var join = from i in intList two separate data sources join j in intList2 based on key properties on i equals j select j; OrderBy/ Orders returned data from var hw = from h in homeworkList OrderByDecendin query by specified property orderby h.DueDate g select h; //now descending order var hw = from h in homeworkList orderby h.DueDate descending select h; ThenBy/ Specifies another property to var hw = from h in homeworkList ThenByDecending order by after the first orderby h.DueDate orderby is processed. thenby h.Class select h; GroupBy Group data by specified var group = from h in homeworkList property. group h by h.DueDate into dueDates select dueDates;

Data Types for LINQ 5

In Memory Objects

LINQ queries cannot be performed upon just any container in the .Net library. However, they can be performed upon most containers. In order for a container to be compatible with LINQ, they must implement the IEnumerable interface. Fortunately this includes standard arrays, .Net containers in the System.Collections, System.Collections.Generic, and System.Collections.ObjectModel Namespaces, and strings. There is also such thing as a generic IEnumerable. Using a generic IEnumerable allows custom data type to be put into an IEnumerable and have the minimum functionality for LINQ to be performed. If circumstances dictate that a custom data type cannot be housed in a generic IEnumerable, a developer can implement the IEnumerable interface in the chosen data type. [1]

SQL Databases

Containers are not the only data source that LINQ can be used to query. SQL databases can also be queried with LINQ. Microsoft SQL Server is the only database currently supported by LINQ. The process for setting up and using a LINQ to SQL data source is more involved than using an IEnumerable data source described earlier. First, a data context must be set up for a database and its tables.

The process of setting up a data context using the designer in Visual Studio is quite simple. All of the code needed for the data context class is created by Visual Studio, needing the developer to only specify the tables and relationships needed. To create a data context, first open up a current project or create a new one in Visual Studio. Next, add using System.Data.Sql; to the source file where the query will be made. Then under the Project menu strip item, select Add New Item. Select LINQ to SQL Classes from the list of items. An empty data context will be added to the project. Next, a connection to an SQL Server database must be made. To do this, open up the Server Explorer pane, which can be found under View -> Other Windows. Right click on Data Connections and select Add Connection. The window in Figure 5 will now appear. 6

Figure 1: Adding an SQL Server database

On this screen, type or select the desired SQL Server name into the Server Name drop down menu. Next, type or select the desired database name into the first drop down menu under Connect to a database and then click OK. 7

Figure 2: SQL Server Database added to Server Explorer

The Server Explorer pane should now be displaying the database, as shown in Figure 6. Clicking on the arrows will show all the tables and views within the database. From the Server Explorer, find the desired table or view from the list and drag it on to the designer pane in the center of the Visual Studio window. After dropping the table or view to the designer, additional properties, such as primary keys and foreign keys, can be set. When the design is saved, the data context code is generated automatically [5]. Figure 7 shows the designer window with a data context with only one view within it. 8

Figure 7: Data Context Designer

To query the data, a new object of the data context type must be created. After that, the LINQ query syntax is the same as the earlier queries to in memory objects. See Figure 8 for an example of a LINQ to SQL query.

LINQ To XML

Continuing on its mission to make a universal and intuitive syntax, LINQ will query an XML document as simply as an SQL database. First, an XDocument object must be created. To do this, add using System.Xml.Linq; to the file where the XML document will be queried. Then, use the XDocument class to load an XML file into memory. An example of loading an XML file and then querying it can be found in Figure 9.

The biggest difference is using the Element function to specify the string to search for in XML document. Also, when using the Element method to get data, a type case must be used (in Figure 9 it is cast as a string). [6] 9

Conclusion

LINQ has been around since 2007, creating a large user base within that amount of time. Because of its versatility, LINQ is still a big player in the development of C# applications of all forms, not just database interaction applications. Due to the versatility that was built into LINQ, its queries could be performed on many types of data. LINQ, combined with Visual Studio, does what used to be the job of the programmer, including inferring data types, creating type classes for database tables, and putting returned data into objects. With LINQ taking care of the tedious work, developers are able to focus more on an application's business logic and other functional requirements.

References

1) Box, D., & Hejlsberg, A. LINQ: .NET Language-Integrated Query. LINQ: .NET Language Integrated Query. Retrieved October 26, 2013, from http://msdn.microsoft.com/en- us/library/bb308959.aspx

2) Obasanjo, Dare. "An Overview of Cω." An Overview of C-Omega. Microsoft, 13 Jan. 2005. Web. 22 Oct. 2013. http://msdn.microsoft.com/en-us/library/ms974195.aspx

3)Ferracchiati, F. LINQ for Visual C# 2008 (pp 7-10). New York, NY: Spinger-Verlag New York Inc, 2008.

4) Lambda Expressions (C# Programming Guide). Lambda Expressions (C# Programming Guide). Retrieved October 29, 2013, from http://msdn.microsoft.com/en- us/library/vstudio/bb397687.aspx

5) Guthrie, S. (2007, May 27). LINQ to SQL (Part 2 - Defining our Data Model Classes). ScottGu's Blog. Retrieved October 29, 2013, from http://weblogs.asp.net/scottgu/archive/2007/05/29/linq-to-sql-part-2-defining-our-data-model- classes.aspx

6)Ferracchiati, F. LINQ for Visual C# 2008 (pp 149-155). New York, NY: Spinger-Verlag New York Inc, 2008.

Recommended publications