Download Microsoft Language Integrate Query (LINQ)

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Data center wikipedia , lookup

Database wikipedia , lookup

Data model wikipedia , lookup

Data analysis wikipedia , lookup

Entity–attribute–value model wikipedia , lookup

SAP IQ wikipedia , lookup

Information privacy law wikipedia , lookup

3D optical data storage wikipedia , lookup

Versant Object Database wikipedia , lookup

Data vault modeling wikipedia , lookup

SQL wikipedia , lookup

Business intelligence wikipedia , lookup

Microsoft SQL Server wikipedia , lookup

Clusterpoint wikipedia , lookup

PL/SQL wikipedia , lookup

Relational model wikipedia , lookup

Database model wikipedia , lookup

Transcript
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]
class Homework
{
public string Class { get; set;}
public DateTime DueDate { get; set;}
}
.
.
.
//Initialize Homework object
Homework h = new Homework {Class = "Calc1", DueDate = new DateTime(2013, 10, 30);
Figure 1: Object Initializers
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]
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]
var thisWillBeInt = 5;
//Inferred as an int type
var thisWillBeList = new List<string>();
//Inferred as List of strings
var thisWillBeAnon = new {Number = 200, Message = "anonymous type"};
//Inferred as a class with two properties, "Number" as int and "Message" as string
//Access data within anonymous type
int myInt = thisWillBeAnon.Number; //myInt will be 200
Figure 2: Var and Anonymous
Types will be "anonymous type"
string myString = thisWillBeAnon.Message;
// myString
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.
int [] integers = {1,4,2,10,6,2};
int filteredNum = integers.Count( i => i == 2);
// filteredNum will be 2 since there are two integers in the list that fulfill the
//lambda expression
Figure 3: Lambda Expressions
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]
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.
List<int> intList = new List<int>{1,4,2,10,6,2};
//Query1
var allInts = from i in intList
select i;
//Query2
var allIntsAgain = intList.Select(i=> i);
//both queries would yield the same data: 1,4,2,10,6.
Figure 4: Basic LINQ query
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
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]
5
Table 1: LINQ Operators
Operator
Where
Description
Filter results based on
boolean statements
Example
Join
Select associated data from
two separate data sources
based on key properties
var join = from i in intList
join j in intList2
on i equals j
select j;
var hw = from h in homeworkList
orderby h.DueDate
select h;
//now descending order
var hw = from h in homeworkList
orderby h.DueDate descending
select h;
var hw = from h in homeworkList
orderby h.DueDate
thenby h.Class
select h;
var group = from h in homeworkList
group h by h.DueDate
into dueDates
select dueDates;
OrderBy/
Orders returned data from
OrderByDecending query by specified property
ThenBy/
ThenByDecending
Specifies another property to
order by after the first
orderby is processed.
GroupBy
Group data by specified
property.
var ints = from i in Intlist
where i >= 0
select i;
Data Types for LINQ
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
6
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.
Figure 5: 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 6: 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.
//AdventureWorksDatabaseDataContext is the data context type.
AdventureWorksDatabaseDataContext AWDatabase = new
AdventureWorksDatabaseDataContext();
//returns the first, middle, and last name of employees with the first name of Bob
var topFive = from v in AWDatabase.vEmployee
where v.FirstName == "Bob"
select new {v.FirstName, v.MiddleName, v.LastName};
Figure 8: Querying an SQL database
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.
9
//<!-- contents of homework.xml file -->
//<?xml version="1.0" encoding="UTF-8"?>
//<homework>
//
<assignment>
//
<class>CAOS</class>
//
<dueDate>04/13/2013</dueDate>
// </assignment>
//
<assignment>
//
<class>CAOS</class>
//
<dueDate>05/01/2013</dueDate>
//
</assignment>
//</homework>
XDocument xml = XDocument.Load(@"homework.xml");
//Gets all assignments for the class named "CAOS"
var caosHomework = from x in xml.Elements("homework").Elements("assignment")
where (string)x.Element("class") == "CAOS"
select x;
Figure 9: Querying XML Documents
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]
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/enus/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
10
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/enus/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-modelclasses.aspx
6)Ferracchiati, F. LINQ for Visual C# 2008 (pp 149-155). New York, NY: Spinger-Verlag New
York Inc, 2008.