Sunteți pe pagina 1din 131

.

NET Language-Integrated Query


After two decades, the industry has reached a stable point in the evolution of object-oriented (OO) programming technologies. Programmers now take for granted features like classes, objects, and methods. In looking at the current and next generation of technologies, it has become apparent that the next big challenge in programming technology is to reduce the complexity of accessing and integrating information that is not natively defined using OO technology. The two most common sources of non-OO information are relational databases and XML. Rather than add relational or XML-specific features to our programming languages and runtime, with the LINQ project we have taken a more general approach and are adding general-purpose query facilities to the .NET Framework that apply to all sources of information, not just relational or XML data. This facility is called .NET Language-Integrated Query (LINQ). We use the term language-integrated query to indicate that query is an integrated feature of the developer's primary programming languages (for example, Visual C#, Visual Basic). Languageintegrated query allows query expressions to benefit from the rich metadata, compile-time syntax checking, static typing and IntelliSense that was previously available only to imperative code. Language-integrated query also allows a single general purpose declarative query facility to be applied to all in-memory information, not just information from external sources. .NET Language-Integrated Query defines a set of general purpose standard query operators that allow traversal, filter, and projection operations to be expressed in a direct yet declarative way in any .NET-based programming language. The standard query operators allow queries to be applied to any IEnumerable<T>-based information source. LINQ allows third parties to augment the set of standard query operators with new domain-specific operators that are appropriate for the target domain or technology. More importantly, third parties are also free to replace the standard query operators with their own implementations that provide additional services such as remote evaluation, query translation, optimization, and so on. By adhering to the conventions of the LINQ pattern, such implementations enjoy the same language integration and tool support as the standard query operators. The extensibility of the query architecture is used in the LINQ project itself to provide implementations that work over both XML and SQL data. The query operators over XML (LINQ to XML) use an efficient, easy-to-use, in-memory XML facility to provide XPath/XQuery functionality in the host programming language. The query operators over relational data (LINQ to SQL) build on the integration of SQL-based schema definitions into the common language runtime (CLR) type system. This integration provides strong typing over relational data while retaining the expressive power of the relational model and the performance of query evaluation directly in the underlying store. Getting Started with Standard Query Operators To see language-integrated query at work, we'll begin with a simple C# 3.0 program that uses the standard query operators to process the contents of an array: using System; using System.Linq; using System.Collections.Generic; class app { static void Main() { string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; IEnumerable<string> query = from s in names where s.Length == 5 orderby s

select s.ToUpper(); foreach (string item in query) Console.WriteLine(item);

} } If you were to compile and run this program, you'd see this as output: BURKE DAVID FRANK To understand how language-integrated query works, we need to dissect the first statement of our program. IEnumerable<string> query = from s in names where s.Length == 5 orderby s select s.ToUpper(); The local variable query is initialized with a query expression. A query expression operates on one or more information sources by applying one or more query operators from either the standard query operators or domain-specific operators. This expression uses three of the standard query operators: Where, OrderBy, and Select. Visual Basic 9.0 supports LINQ as well. Here's the preceding statement written in Visual Basic 9.0: Dim query As IEnumerable(Of String) = From s in names _ Where s.Length = 5 _ Order By s _ Select s.ToUpper() Both the C# and Visual Basic statements shown here use query expressions. Like the foreach statement, query expressions are convenient declarative shorthand over code you could write manually. The statements above are semantically identical to the following explicit syntax shown in C#: IEnumerable<string> query = names .Where(s => s.Length == 5) .OrderBy(s => s) .Select(s => s.ToUpper()); This form of query is called a method-based query. The arguments to the Where, OrderBy, and Select operators are called lambda expressions, which are fragments of code much like delegates. They allow the standard query operators to be defined individually as methods and strung together using dot notation. Together, these methods form the basis for an extensible query language. Language Features Supporting the LINQ Project LINQ is built entirely on general purpose language features, some of which are new to C# 3.0 and Visual Basic 9.0. Each of these features has utility on its own, yet collectively these features provide an extensible way to define queries and queryable APIs. In this section we explore these language features and how they contribute to a much more direct and declarative style of queries. Lambda Expressions and Expression Trees Many query operators allow the user to provide a function that performs filtering, projection, or key extraction. The query facilities build on the concept of lambda expressions, which provide developers with a convenient way to write functions that can be passed as arguments for subsequent evaluation. Lambda expressions are similar to CLR delegates and must adhere to a method signature defined by a delegate type. To illustrate this, we can expand the statement above into an equivalent but more explicit form using the Func delegate type: Func<string, bool> filter = s => s.Length == 5;

Func<string, string> extract = s => s; Func<string, string> project = s => s.ToUpper(); IEnumerable<string> query = names.Where(filter) .OrderBy(extract) .Select(project); Lambda expressions are the natural evolution of anonymous methods in C# 2.0. For example, we could have written the previous example using anonymous methods like this: Func<string, bool> filter = delegate (string s) { return s.Length == 5; }; Func<string, string> extract = delegate (string s) { return s; }; Func<string, string> project = delegate (string s) { return s.ToUpper(); }; IEnumerable<string> query = names.Where(filter) .OrderBy(extract) .Select(project); In general, the developer is free to use named methods, anonymous methods, or lambda expressions with query operators. Lambda expressions have the advantage of providing the most direct and compact syntax for authoring. More importantly, lambda expressions can be compiled as either code or data, which allows lambda expressions to be processed at runtime by optimizers, translators, and evaluators. The namespace System.Linq.Expressions defines a distinguished generic type, Expression<T>, which indicates that an expression tree is desired for a given lambda expression rather than a traditional IL-based method body. Expression trees are efficient inmemory data representations of lambda expressions and make the structure of the expression transparent and explicit. The determination of whether the compiler will emit executable IL or an expression tree is determined by how the lambda expression is used. When a lambda expression is assigned to a variable, field, or parameter whose type is a delegate, the compiler emits IL that is identical to that of an anonymous method. When a lambda expression is assigned to a variable, field, or parameter whose type is Expression<T> for some delegate type T, the compiler emits an expression tree instead. For example, consider the following two variable declarations: Func<int, bool> f = n => n < 5; Expression<Func<int, bool>> e = n => n < 5; The variable f is a reference to a delegate that is directly executable: bool isSmall = f(2); // isSmall is now true The variable e is a reference to an expression tree that is not directly executable: bool isSmall = e(2); // compile error, expressions == data Unlike delegates, which are effectively opaque code, we can interact with the expression tree just like any other data structure in our program. Expression<Func<int, bool>> filter = n => n < 5; BinaryExpression body = (BinaryExpression)filter.Body; ParameterExpression left = (ParameterExpression)body.Left; ConstantExpression right = (ConstantExpression)body.Right;

Console.WriteLine("{0} {1} {2}", left.Name, body.NodeType, right.Value); The above example decomposes the expression tree at runtime and prints the following string: n LessThan 5 This ability to treat expressions as data at runtime is critical to enable an ecosystem of third-party libraries that leverage the base query abstractions that are part of the platform. The LINQ to SQL data access implementation leverages this facility to translate expression trees to T-SQL statements suitable for evaluation in the store. Extension Methods Lambda expressions are one important piece of the query architecture. Extension methods are another. Extension methods combine the flexibility of "duck typing" made popular in dynamic languages with the performance and compile-time validation of statically-typed languages. With extension methods third parties may augment the public contract of a type with new methods while still allowing individual type authors to provide their own specialized implementation of those methods. Extension methods are defined in static classes as static methods, but are marked with the [System.Runtime.CompilerServices.Extension] attribute in CLR metadata. Languages are encouraged to provide a direct syntax for extension methods. In C#, extension methods are indicated by the this modifier which must be applied to the first parameter of the extension method. Let's look at the definition of the simplest query operator, Where: namespace System.Linq { using System; using System.Collections.Generic; public static class Enumerable { public static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, bool> predicate) { foreach (T item in source) if (predicate(item)) yield return item;

} }

} The type of the first parameter of an extension method indicates what type the extension applies to. In the example above, the Where extension method extends the type IEnumerable<T>. Because Where is a static method, we can invoke it directly just like any other static method: IEnumerable<string> query = Enumerable.Where(names, s => s.Length < 6); However, what makes extension methods unique is that they can also be invoked using instance syntax: IEnumerable<string> query = names.Where(s => s.Length < 6); Extension methods are resolved at compile-time based on which extension methods are in scope. When a namespace is imported with a using statement in C# or an Import statement in Visual Basic, all extension methods that are defined by static classes from that namespace are brought into scope. The standard query operators are defined as extension methods in the type System.Linq.Enumerable. When examining the standard query operators, you'll notice that all but a few of them are defined in terms of the IEnumerable<T> interface. This means that every IEnumerable<T>-compatible information source gets the standard query operators simply by adding the following using statement in C#:

using System.Linq; // makes query operators visible Users who want to replace the standard query operators for a specific type may either: define their own same-named methods on the specific type with compatible signatures, or define new samenamed extension methods that extend the specific type. Users who want to eschew the standard query operators altogether can simply not put System.Linq into scope and write their own extension methods for IEnumerable<T>. Extension methods are given the lowest priority in terms of resolution and are only used if there is no suitable match on the target type and its base types. This allows user-defined types to provide their own query operators that take precedence over the standard operators. For example, consider the following custom collection: public class MySequence : IEnumerable<int> { public IEnumerator<int> GetEnumerator() { for (int i = 1; i <= 10; i++) yield return i; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerable<int> Where(Func<int, bool> filter) { for (int i = 1; i <= 10; i++) if (filter(i)) yield return i; } } Given this class definition, the following program will use the MySequence.Where implementation, not the extension method, as instance methods take precedence over extension methods: MySequence s = new MySequence(); foreach (int item in s.Where(n => n > 3)) Console.WriteLine(item); The OfType operator is one of the few standard query operators that doesn't extend an IEnumerable<T>-based information source. Let's look at the OfTypequery operator: public static IEnumerable<T> OfType<T>(this IEnumerable source) { foreach (object item in source) if (item is T) yield return (T)item; } OfType accepts not only IEnumerable<T>-based sources, but also sources that are written against the non-parameterized IEnumerable interface that was present in version 1.0 of the .NET Framework. The OfType operator allows users to apply the standard query operators to classic .NET collections like this: // "classic" cannot be used directly with query operators IEnumerable classic = new OlderCollectionType(); // "modern" can be used directly with query operators IEnumerable<object> modern = classic.OfType<object>(); In this example, the variable modern yields the same sequence of values as does classic. However, its type is compatible with modern IEnumerable<T> code, including the standard query operators. The OfType operator is also useful for newer information sources, as it allows filtering values from a source based on type. When producing the new sequence,OfType simply omits members of the original sequence that are not compatible with the type argument. Consider this simple program that extracts strings from a heterogeneous array:

object[] vals = { 1, "Hello", true, "World", 9.1 }; IEnumerable<string> justStrings = vals.OfType<string>(); When we enumerate the justStrings variable in a foreach statement, we'll get a sequence of two strings: "Hello" and "World." Deferred Query Evaluation Observant readers may have noted that the standard Where operator is implemented using the yield construct introduced in C# 2.0. This implementation technique is common for all the standard operators that return sequences of values. The use of yield has an interesting benefit which is that the query is not actually evaluated until it is iterated over, either with a foreach statement or by manually using the underlying GetEnumerator and MoveNext methods. This deferred evaluation allows queries to be kept as IEnumerable<T>-based values that can be evaluated multiple times, each time yielding potentially different results. For many applications, this is exactly the behavior that is desired. For applications that want to cache the results of query evaluation, two operators, ToList andToArray, are provided that force the immediate evaluation of the query and return either a List<T> or an array containing the results of the query evaluation. To see how deferred query evaluation works consider this program that runs a simple query over an array: // declare a variable containing some strings string[] names = { "Allen", "Arthur", "Bennett" }; // declare a variable that represents a query IEnumerable<string> ayes = names.Where(s => s[0] == 'A'); // evaluate the query foreach (string item in ayes) Console.WriteLine(item); // modify the original information source names[0] = "Bob"; // evaluate the query again, this time no "Allen" foreach (string item in ayes) Console.WriteLine(item); The query is evaluated each time the variable ayes is iterated over. To indicate that a cached copy of the results is needed, we can simply append a ToList orToArray operator to the query like this: // declare a variable containing some strings string[] names = { "Allen", "Arthur", "Bennett" }; // declare a variable that represents the result // of an immediate query evaluation string[] ayes = names.Where(s => s[0] == 'A').ToArray(); // iterate over the cached query results foreach (string item in ayes) Console.WriteLine(item); // modifying the original source has no effect on ayes names[0] = "Bob"; // iterate over result again, which still contains "Allen" foreach (string item in ayes) Console.WriteLine(item);

Both ToArray and ToList force immediate query evaluation. The same is true for the standard query operators that return singleton values (for example: First,ElementAt, Sum, Average, All, Any). The IQueryable<T> Interface The same deferred execution model is usually desired for data sources that implement the query functionality by using expression trees, such as LINQ to SQL. These data sources can benefit from implementing the IQueryable<T> interface for which all the query operators required by the LINQ pattern are implemented by using expression trees. Each IQueryable<T> has a representation of "the code needed to run the query" in the form of an expression tree. All the deferred query operators return a new IQueryable<T> that augments that expression tree with a representation of a call to that query operator. Thus, when it becomes time to evaluate the query, typically because the IQueryable<T> is enumerated, the data source can process the expression tree representing the whole query in one batch. As an example, a complicated LINQ to SQL query obtained by numerous calls to query operators may result in only a single SQL query getting sent to the database. The benefit for data source implementers of reusing this deferring functionality by implementing the IQueryable<T> interface is obvious. To the clients who write the queries, on the other hand, it is a great advantage to have a common type for remote information sources. Not only does it allow them to write polymorphic queries that can be used against different sources of data, but it also opens up the possibility for writing queries that go across domains. Initializing Compound Values Lambda expressions and extension methods provide us with everything we need for queries that simply filter members out of a sequence of values. Most query expressions also perform projection over those members, effectively transforming members of the original sequence into members whose value and type may differ from the original. To support writing these transforms, LINQ relies on a new construct called object initializers to create new instances of structured types. For the rest of this document, we'll assume the following type has been defined: public class Person { string name; int age; bool canCode; public string Name { get { return name; } set { name = value; } } public int Age { get { return age; } set { age = value; } } public bool CanCode { get { return canCode; } set { canCode = value; } } } Object initializers allow us to easily construct values based on the public fields and properties of a type. For example, to create a new value of type Person, we can write this statement: Person value = new Person { Name = "Chris Smith", Age = 31, CanCode = false }; Semantically, this statement is equivalent to the following sequence of statements: Person value = new Person(); value.Name = "Chris Smith";

value.Age = 31; value.CanCode = false; Object initializers are an important feature for language-integrated query, as they allow the construction of new structured values in contexts where only expressions are allowed (such as within lambda expressions and expression trees). For example, consider this query expression that creates a new Person value for each value in the input sequence: IEnumerable<Person> query = names.Select(s => new Person { Name = s, Age = 21, CanCode = s.Length == 5 }); Object initialization syntax is also convenient for initializing arrays of structured values. For example, consider this array variable that is initialized using individual object initializers: static Person[] people = { new Person { Name="Allen Frances", Age=11, CanCode=false }, new Person { Name="Burke Madison", Age=50, CanCode=true }, new Person { Name="Connor Morgan", Age=59, CanCode=false }, new Person { Name="David Charles", Age=33, CanCode=true }, new Person { Name="Everett Frank", Age=16, CanCode=true }, }; Structured Values and Types The LINQ project supports a data-centric programming style in which some types exist primarily to provide a static "shape" over a structured value rather than a full-blown object with both state and behavior. Taking this premise to its logical conclusion, it is often the case that all the developer cares about is the structure of the value, and the need for a named type for that shape is of little use. This leads to the introduction of anonymous types that allow new structures to be defined "inline" with their initialization. In C#, the syntax for anonymous types is similar to the object initialization syntax except that the name of the type is omitted. For example, consider the following two statements: object v1 = new Person { Name = "Brian Smith", Age = 31, CanCode = false }; object v2 = new { // note the omission of type name Name = "Brian Smith", Age = 31, CanCode = false }; The variables v1 and v2 both point to an in-memory object whose CLR type has three public properties Name, Age, and CanCode. The variables differ in that v2refers to an instance of an anonymous type. In CLR terms, anonymous types are no different than any other type. What makes anonymous types special is that they have no meaningful name in your programming language. The only way to create instances of an anonymous type is using the syntax shown above. To allow variables to refer to instances of anonymous types yet still benefit from static typing, C# introduces implicitly typed local variables: The var keyword may be used in place of the type name for local variable declarations. For example, consider this legal C# 3.0 program: var s = "Bob"; var n = 32; var b = true; The var keyword tells the compiler to infer the type of the variable from the static type of the expression used to initialize the variable. In this example, the types ofs, n, and b are string, int, and bool, respectively. This program is identical to the following: string s = "Bob"; int n = 32; bool b = true; The var keyword is a convenience for variables whose types have meaningful names, but it is a

necessity for variables that refer to instances of anonymous types. var value = new { Name = " Brian Smith", Age = 31, CanCode = false }; In the example above, variable value is of an anonymous type whose definition is equivalent to the following pseudo-C#: internal class ??? { string _Name; int _Age; bool _CanCode; public string Name { get { return _Name; } set { _Name = value; } } public int Age{ get { return _Age; } set { _Age = value; } } public bool CanCode { get { return _CanCode; } set { _CanCode = value; } } public bool Equals(object obj) { ... } public bool GetHashCode() { ... } } Anonymous types cannot be shared across assembly boundaries; however, the compiler ensures that there is at most one anonymous type for a given sequence of property name/type pairs within each assembly. Because anonymous types are often used in projections to select one or more members of an existing structured value, we can simply reference fields or properties from another value in the initialization of an anonymous type. This results in the new anonymous type getting a property whose name, type, and value are all copied from the referenced property or field. For instance, consider this example that creates a new structured value by combining properties from other values: var bob = new Person { Name = "Bob", Age = 51, CanCode = true }; var jane = new { Age = 29, FirstName = "Jane" }; var couple = new { Husband = new { bob.Name, bob.Age }, Wife = new { Name = jane.FirstName, jane.Age } }; int ha = couple.Husband.Age; // ha == 51 string wn = couple.Wife.Name; // wn == "Jane" The referencing of fields or properties shown above is simply a convenient syntax for writing the following more explicit form: var couple = new { Husband = new { Name = bob.Name, Age = bob.Age }, Wife = new { Name = jane.FirstName, Age = jane.Age } }; In both cases, the couple variable gets its own copy of the Name and Age properties from bob and jane.

Anonymous types are most often used in the select clause of a query. For example, consider the following query: var query = people.Select(p => new { p.Name, BadCoder = p.Age == 11 }); foreach (var item in query) Console.WriteLine("{0} is a {1} coder", item.Name, item.BadCoder ? "bad" : "good"); In this example, we were able to create a new projection over the Person type that exactly matched the shape we needed for our processing code yet still gave us the benefits of a static type. More Standard Query Operators On top of the basic query facilities described above, a number of operators provide useful ways of manipulating sequences and composing queries, giving the user a high degree of control over the result within the convenient framework of the standard query operators. Sorting and Grouping In general, the evaluation of a query results in a sequence of values that are produced in some order that is intrinsic in the underlying information sources. To give developers explicit control over the order in which these values are produced, standard query operators are defined for controlling the order. The most basic of these operators is the OrderBy operator. The OrderBy and OrderByDescending operators can be applied to any information source and allow the user to provide a key extraction function that produces the value that is used to sort the results. OrderBy and OrderByDescending also accept an optional comparison function that can be used to impose a partial order over the keys. Let's look at a basic example: string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; // unity sort var s1 = names.OrderBy(s => s); var s2 = names.OrderByDescending(s => s); // sort by length var s3 = names.OrderBy(s => s.Length); var s4 = names.OrderByDescending(s => s.Length); The first two query expressions produce new sequences that are based on sorting the members of the source based on string comparison. The second two queries produce new sequences that are based on sorting the members of the source based on the length of each string. To allow multiple sort criteria, both OrderBy and OrderByDescending return OrderedSequence<T> rather than the generic IEnumerable<T>. Two operators are defined only on OrderedSequence<T>, namely ThenBy and ThenByDescending which apply an additional (subordinate) sort criterion.ThenBy/ThenByDescending themselves return OrderedSequence<T>, allowing any number of ThenBy/ThenByDescending operators to be applied: string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; var s1 = names.OrderBy(s => s.Length).ThenBy(s => s); Evaluating the query referenced by s1 in this example would yield the following sequence of values:

"Burke", "David", "Frank", "Albert", "Connor", "George", "Harris", "Everett" In addition to the OrderBy family of operators, the standard query operators also include a Reverse operator. Reverse simply enumerates over a sequence and yields the same values in reverse order. Unlike OrderBy, Reverse doesn't consider the actual values themselves in determining the order, rather it relies solely on the order the values are produced by the underlying source. The OrderBy operator imposes a sort order over a sequence of values. The standard query operators also include the GroupBy operator, which imposes a partitioning over a sequence of values based on a key extraction function. The GroupBy operator returns a sequence of IGrouping values, one for each distinct key value that was encountered. An IGrouping is an IEnumerable that additionally contains the key that was used to extract its contents: public interface IGrouping<K, T> : IEnumerable<T> { public K Key { get; } } The simplest application of GroupBy looks like this: string[] names = { "Albert", "Burke", "Connor", "David", "Everett", "Frank", "George", "Harris"}; // group by length var groups = names.GroupBy(s => s.Length); foreach (IGrouping<int, string> group in groups) { Console.WriteLine("Strings of length {0}", group.Key); foreach (string value in group) Console.WriteLine(" {0}", value);

} When run, this program prints out the following: Strings of length 6 Albert Connor George Harris Strings of length 5 Burke David Frank Strings of length 7 Everett A la Select, GroupBy allows you to provide a projection function that is used to populate members of the groups. string[] names = { "Albert", "Burke", "Connor", "David", "Everett", "Frank", "George", "Harris"}; // group by length var groups = names.GroupBy(s => s.Length, s => s[0]); foreach (IGrouping<int, char> group in groups) { Console.WriteLine("Strings of length {0}", group.Key); foreach (char value in group) Console.WriteLine(" {0}", value); } This variation prints the following:

Strings of length 6 A C G H Strings of length 5 B D F Strings of length 7 E Note From this example that the projected type does not need to be the same as the source. In this case, we created a grouping of integers to characters from a sequence of strings.

Aggregation Operators Several standard query operators are defined for aggregating a sequence of values into a single value. The most general aggregation operator is Aggregate, which is defined like this: public static U Aggregate<T, U>(this IEnumerable<T> source, U seed, Func<U, T, U> func) { U result = seed; foreach (T element in source) result = func(result, element); return result; } The Aggregate operator makes it simple to perform a calculation over a sequence of values. Aggregate works by calling the lambda expression once for each member of the underlying sequence. Each time Aggregate calls the lambda expression, it passes both the member from the sequence and an aggregated value (the initial value is the seed parameter to Aggregate). The result of the lambda expression replaces the previous aggregated value, and Aggregate returns the final result of the lambda expression. For example, this program uses Aggregate to accumulate the total character count over an array of strings: string[] names = { "Albert", "Burke", "Connor", "David", "Everett", "Frank", "George", "Harris"}; int count = names.Aggregate(0, (c, s) => c + s.Length); // count == 46 In addition to the general purpose Aggregate operator, the standard query operators also include a general purpose Count operator and four numeric aggregation operators (Min, Max, Sum, and Average) that simplify these common aggregation operations. The numeric aggregation functions work over sequences of numeric types (for example, int, double, decimal) or over sequences of arbitrary values as long as a function is provided that projects members of the sequence into a numeric type. This program illustrates both forms of the Sum operator just described: int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; string[] names = { "Albert", "Burke", "Connor", "David", "Everett", "Frank", "George", "Harris"}; int total1 = numbers.Sum(); // total1 == 55 int total2 = names.Sum(s => s.Length); // total2 == 46 Note The second Sum statement is equivalent to the previous example

using Aggregate.

Select vs. SelectMany The Select operator requires the transform function to produce one value for each value in the source sequence. If your transform function returns a value that is itself a sequence, it is up to the consumer to traverse the sub-sequences manually. For example, consider this program that breaks strings into tokens using the existing String.Split method: string[] text = { "Albert was here", "Burke slept late", "Connor is happy" }; var tokens = text.Select(s => s.Split(' ')); foreach (string[] line in tokens) foreach (string token in line) Console.Write("{0}.", token); When run, this program prints out the following text: Albert.was.here.Burke.slept.late.Connor.is.happy. Ideally, we would have liked our query to have returned a coalesced sequence of tokens and not exposed the intermediate string[] to the consumer. To achieve this, we use the SelectMany operator instead of the Select operator. The SelectMany operator works similarly to the Select operator. It differs in that the transform function is expected to return a sequence that is then expanded by the SelectMany operator. Here's our program rewritten using SelectMany: string[] text = { "Albert was here", "Burke slept late", "Connor is happy" }; var tokens = text.SelectMany(s => s.Split(' ')); foreach (string token in tokens) Console.Write("{0}.", token); The use of SelectMany causes each intermediate sequence to be expanded as part of normal evaluation. SelectMany is ideal for combining two information sources: string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; var query = names.SelectMany(n => people.Where(p => n.Equals(p.Name)) ); In the lambda expression passed to SelectMany, the nested query applies to a different source, but has in scope the n parameter passed in from the outer source. Thus people.Where is called once for each n, with the resulting sequences flattened by SelectMany for the final output. The result is a sequence of all the people whose name appears in the names array.

Join Operators In an object oriented program, objects that are related to each other will typically be linked with object references which are easy to navigate. The same usually does not hold true for external information sources, where data entries often have no option but to "point" to each other symbolically, with IDs or other data that can uniquely identify the entity pointed to. The concept of joins refers to the operation of bringing the elements of a sequence together with the elements they "match up with" from another sequence. The previous example with SelectMany actually does exactly that, matching up strings with people whose names are those strings. However, for this particular purpose, the SelectMany approach isn't very efficientit will loop through all the elements of people for each and every element of names. By bringing all the information of this scenariothe two information sources and the "keys" by which they are matched uptogether in one method call, the Join operator is able to do a much better job: string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; var query = names.Join(people, n => n, p => p.Name, (n,p) => p); This is a bit of a mouthful, but see how the pieces fit together: The Join method is called on the "outer" data source, names. The first argument is the "inner" data source, people. The second and third arguments are lambda expressions to extract keys from the elements of the outer and inner sources, respectively. These keys are what the Join method uses to match up the elements. Here we want the names themselves to match the Name property of the people. The final lambda expression is then responsible for producing the elements of the resulting sequence: It is called with each pair of matching elements n and p, and is used to shape the result. In this case we choose to discard the n and return the p. The end result is the list of Person elements of people whose Name is in the list of names. A more powerful cousin of Join is the GroupJoin operator. GroupJoin differs from Join in the way the result-shaping lambda expression is used: Instead of being invoked with each individual pair of outer and inner elements, it will be called only once for each outer element, with a sequence of all of the inner elements that match that outer element. To make that concrete: string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; var query = names.GroupJoin(people, n => n, p => p.Name, (n, matching) => new { Name = n, Count = matching.Count() } ); This call produces a sequence of the names you started out with paired with the number of people who have that name. Thus, the GroupJoin operator allows you to base your results on the whole "set of matches" for an outer element. Query Syntax The existing foreach statement in C# provides a declarative syntax for iteration over the .NET Frameworks IEnumerable/IEnumerator methods. The foreachstatement is strictly optional, but it has proven to be a very convenient and popular language mechanism. Building on this precedent, query expressions simplifies queries with a declarative syntax for the most common query operators: Where, Join, GroupJoin, Select,SelectMany, GroupBy, OrderBy, ThenBy, OrderB yDescending, ThenByDescending, and Cast. Let's start by looking at the simple query we began this paper with: IEnumerable<string> query = names .Where(s => s.Length == 5) .OrderBy(s => s)

.Select(s => s.ToUpper()); Using a query expression we can rewrite this exact statement like this: IEnumerable<string> query = from s in names where s.Length == 5 orderby s select s.ToUpper(); Like the foreach statement in C#, query expressions are more compact and easier to read, but are completely optional. Every expression that can be written as a query expression has a corresponding (albeit more verbose) syntax using dot notation. Let's begin by looking at the basic structure of a query expression. Every syntactic query expression in C# begins with a from clause and ends with either a selector group clause. The initial from clause can be followed by zero or more from, let, where, join and orderby clauses. Each from clause is a generator that introduces a range variable over a sequence; each let clause gives a name to the result of an expression; and each where clause is a filter that excludes items from the result. Every join clause correlates a new data source with the results of the preceding clauses. An orderby clause specifies an ordering for the result: query-expression ::= from-clause query-body query-body ::= query-body-clause* final-query-clause query-continuation? query-body-clause ::= (from-clause | join-clause | let-clause | where-clause | orderby-clause) from-clause ::= from itemName in srcExpr join-clause ::= join itemName in srcExpr on keyExpr equals keyExpr (into itemName)? let-clause ::= let itemName = selExpr where-clause ::= where predExpr orderby-clause ::= orderby (keyExpr (ascending | descending)?)* final-query-clause ::= (select-clause | groupby-clause) select-clause ::= select selExpr groupby-clause ::= group selExpr by keyExpr query-continuation ::= into itemName query-body For example, consider these two query expressions: var query1 = from p in people where p.Age > 20 orderby p.Age descending, p.Name select new { p.Name, Senior = p.Age > 30, p.CanCode };

var query2 = from p in people where p.Age > 20 orderby p.Age descending, p.Name group new { p.Name, Senior = p.Age > 30, p.CanCode } by p.CanCode; The compiler treats these query expressions as if they were written using the following explicit dot-notation: var query1 = people.Where(p => p.Age > 20) .OrderByDescending(p => p.Age) .ThenBy(p => p.Name) .Select(p => new { p.Name, Senior = p.Age > 30, p.CanCode }); var query2 = people.Where(p => p.Age > 20) .OrderByDescending(p => p.Age) .ThenBy(p => p.Name) .GroupBy(p => p.CanCode, p => new { p.Name, Senior = p.Age > 30, p.CanCode }); Query expressions undergo a mechanical translation into calls of methods with specific names. The exact query operator implementation that is chosen therefore depends both on the type of the variables being queried and the extension methods that are in scope. The query expressions shown so far have only used one generator. When more than one generator is used, each subsequent generator is evaluated in the context of its predecessor. For example, consider this slight modification to our query: var query = from s1 in names where s1.Length == 5 from s2 in names where s1 == s2 select s1 + " " + s2; When run against this input array: string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David" }; we get the following results: Burke Burke Frank Frank David David The query expression above expands to this dot-notation expression: var query = names.Where(s1 => s1.Length == 5) .SelectMany(s1 => names, (s1,s2) => new {s1,s2}) .Where($1 => $1.s1 == $1.s2) .Select($1 => $1.s1 + " " + $1.s2); Note This version of SelectMany takes an extra lambda expression which is used to produce the result based on elements from the outer and inner sequences. In this lambda expression, the two range variables are collected in an anonymous type. The compiler invents a variable name $1 to denote that anonymous type in subsequent lambda expressions.

A special kind of generator is the join clause, which will introduce elements of another source that match up with the elements of the preceding clauses according to given keys. A join clause may yield the matching elements one by one, but if specified with an into clause, the matching elements will be given as a group: var query = from n in names join p in people on n equals p.Name into matching select new { Name = n, Count = matching.Count() }; Not surprisingly, this query expands quite directly into one we have seen before: var query = names.GroupJoin(people, n => n, p => p.Name, (n, matching) => new { Name = n, Count = matching.Count() } ); It is often useful to treat the results of one query as a generator in a subsequent query. To support this, query expressions use the into keyword to splice a new query expression after a select or group clause. This is called a query continuation. The into keyword is especially useful for post-processing the results of a group by clause. For example, consider this program: var query = from item in names orderby item group item by item.Length into lengthGroups orderby lengthGroups.Key descending select lengthGroups; foreach (var group in query) { Console.WriteLine("Strings of length {0}", group.Key); foreach (var val in group) Console.WriteLine(" {0}", val);

} This program outputs the following:

Strings of length 7 Everett Strings of length 6 Albert Connor George Harris Strings of length 5 Burke David Frank In this section it was described how C# implements query expressions. Other languages may elect to support additional query operators with explicit syntax, or not to have query expressions at all. It is important to note that the query syntax is by no means hard-wired to the standard query operators. It is a purely syntactic feature that applies to anything which fulfills the query pattern by implementing underlying methods with the appropriate names and signatures. The standard query operators described above do so by using extension methods to augment the IEnumerable<T> interface. Developers may exploit the query syntax on any type they wish, as long as they make sure that it adheres to the query pattern, either by direct implementation of the necessary methods or by adding them as extension methods. This extensibility is exploited in the LINQ project itself by the provision of two LINQ-enabled API's, namely LINQ to SQL, which implements the LINQ pattern for SQL-based data access, and LINQ to XML which allows LINQ queries over XML data. Both of these are described in the following sections.

LINQ to SQL: SQL Integration .NET Language-Integrated Query can be used to query relational data stores without leaving the syntax or compile-time environment of the local programming language. This facility, code-named LINQ to SQL, takes advantage of the integration of SQL schema information into CLR metadata. This integration compiles SQL table and view definitions into CLR types that can be accessed from any language. LINQ to SQL defines two core attributes, [Table] and [Column], which indicate which CLR types and properties correspond to external SQL data. The [Table]attribute can be applied to a class and associates the CLR type with a named SQL table or view. The [Column] attribute can be applied to any field or property and associates the member with a named SQL column. Both attributes are parameterized to allow SQL-specific metadata to be retained. For example, consider this simple SQL schema definition: create table People ( Name nvarchar(32) primary key not null, Age int not null, CanCode bit not null ) create table Orders ( OrderID nvarchar(32) primary key not null, Customer nvarchar(32) not null, Amount int ) The CLR equivalent looks like this: [Table(Name="People")] public class Person { [Column(DbType="nvarchar(32) not null", Id=true)] public string Name; [Column] public int Age; [Column] public bool CanCode;

[Table(Name="Orders")] public class Order { [Column(DbType="nvarchar(32) not null", Id=true)] public string OrderID; [Column(DbType="nvarchar(32) not null")] public string Customer; [Column] public int? Amount; Note This example that nullable columns map to nullable types in the CLR (nullable types first appeared in version 2.0 of the .NET Framework), and that for SQL types that don't have a 1:1 correspondence with a CLR type (for example, nvarchar, char, text), the original SQL type is retained in the CLR metadata. To issue a query against a relational store, the LINQ to SQL implementation of the LINQ pattern translates the query from its expression tree form into a SQL expression and ADO.NET DbCommand object suitable for remote evaluation. For example, consider this simple query:

// establish a query context over ADO.NET sql connection DataContext context = new DataContext( "Initial Catalog=petdb;Integrated Security=sspi"); // grab variables that represent the remote tables that // correspond to the Person and Order CLR types Table<Person> custs = context.GetTable<Person>(); Table<Order> orders = context.GetTable<Order>(); // build the query var query = from c in custs from o in orders where o.Customer == c.Name select new { c.Name, o.OrderID, o.Amount, c.Age }; // execute the query foreach (var item in query) Console.WriteLine("{0} {1} {2} {3}", item.Name, item.OrderID, item.Amount, item.Age); The DataContext type provides a lightweight translator that translates the standard query operators to SQL. DataContext uses the existing ADO.NETIDbConnection for accessing the store and can be initialized with either an established ADO.NET connection object or a connection string that can be used to create one. The GetTable method provides IEnumerable-compatible variables that can be used in query expressions to represent the remote table or view. Calls to GetTabledo not cause any interaction with the databaserather they represent the potential to interact with the remote table or view using query expressions. In our example above, the query does not get transmitted to the store until the program iterates over the query expression, in this case using the foreach statement in C#. When the program first iterates over the query, the DataContext machinery translates the expression tree into the following SQL statement that is sent to the store: SELECT [t0].[Age], [t1].[Amount], [t0].[Name], [t1].[OrderID] FROM [Customers] AS [t0], [Orders] AS [t1] WHERE [t1].[Customer] = [t0].[Name] It's important to note that by building query capability directly into the local programming language, developers get the full power of the relational model without having to statically bake the relationships into the CLR type. That stated, comprehensive object/relational mapping can also take advantage of this core query capability for users that want that functionality. LINQ to SQL provides object-relational mapping functionality with which the developer can define and navigate relationships between objects. You can refer to Orders as a property of the Customer class using mapping, so that you do not need explicit joins to tie the two together. External mapping files allow the mapping to be separated from the object model for richer mapping capabilities. LINQ to XML: XML Integration .NET Language-Integrated Query for XML (LINQ to XML) allows XML data to be queried by using the standard query operators as well as tree-specific operators that provide XPath-like navigation through descendants, ancestors, and siblings. It provides an efficient in-memory representation for XML that integrates with the existing System.Xml reader/writer infrastructure and is easier to use than W3C DOM. There are three types that do most of the work of integrating XML with queries: XName, XElement and XAttribute.

XName provides an easy-to-use way to deal with the namespace-qualified identifiers (QNames) used as both element and attribute names. XName handles the efficient atomization of identifiers transparently and allows either symbols or plain strings to be used wherever a QName is needed. XML elements and attributes are represented using XElement and XAttribute respectively. XElement and XAttribute support normal construction syntax, allowing developers to write XML expressions using a natural syntax: var e = new XElement("Person", new XAttribute("CanCode", true), new XElement("Name", "Loren David"), new XElement("Age", 31)); var s = e.ToString(); This corresponds to the following XML: <Person CanCode="true"> <Name>Loren David</Name> <Age>31</Age> </Person> Notice that no DOM-based factory pattern was needed to create the XML expression, and that the ToString implementation yielded the textual XML. XML elements can also be constructed from an existing XmlReader or from a string literal: var e2 = XElement.Load(xmlReader); var e1 = XElement.Parse( @"<Person CanCode='true'> <Name>Loren David</Name> <Age>31</Age> </Person>"); XElement also supports emitting XML using the existing XmlWriter type. XElement dovetails with the query operators, allowing developers to write queries against nonXML information and produce XML results by constructingXElements in the body of a select clause: var query = from p in people where p.CanCode select new XElement("Person", new XAttribute("Age", p.Age), p.Name); This query returns a sequence of XElements. To allow XElements to be built out of the result of this kind of query, the XElement constructor allows sequences of elements to be passed as arguments directly: var x = new XElement("People", from p in people where p.CanCode select new XElement("Person", new XAttribute("Age", p.Age), p.Name)); This XML expression results in the following XML: <People> <Person Age="11">Allen Frances</Person> <Person Age="59">Connor Morgan</Person> </People> The statement above has a direct translation to Visual Basic. However, Visual Basic 9.0 also supports the use of XML literals, which allow query expressions to be expressed using a declarative XML syntax directly from Visual Basic. The previous example could be constructed with

the Visual Basic statement: Dim x = _ <People> <%= From p In people __ Where p.CanCode _ Select <Person Age=<%= p.Age %>>p.Name</Person> _ %> </People> The examples so far have shown how to construct new XML values using language-integrated query. The XElement and XAttribute types also simplify theextraction of information from XML structures. XElement provides accessor methods that allow query expressions to be applied to the traditional XPath axes. For example, the following query extracts just the names from the XElement shown above: IEnumerable<string> justNames = from e in x.Descendants("Person") select e.Value; //justNames = ["Allen Frances", "Connor Morgan"] To extract structured values from the XML, we simply use an object initializer expression in our select clause: IEnumerable<Person> persons = from e in x.Descendants("Person") select new Person { Name = e.Value, Age = (int)e.Attribute("Age") }; Note that both XAttribute and XElement support explicit conversions to extract the text value as a primitive type. To deal with missing data, we can simply cast to a nullable type: IEnumerable<Person> persons = from e in x.Descendants("Person") select new Person { Name = e.Value, Age = (int?)e.Attribute("Age") ?? 21 }; In this case, we use a default value of 21 when the Age attribute is missing. Visual Basic 9.0 provides direct language support for the Elements, Attribute, and Descendants accessor methods of XElement, allowing XML-based data to be accessed using a more compact and direct syntax called XML axis properties. We can use this functionality to write the preceding C# statement like this: Dim persons = _ From e In x...<Person> _ Select new Person { _ .Name = e.Value, _ .Age = IIF(e.@Age, 21) _ } In Visual Basic, x...<Person> gets all items in the Descendants collection of x with the name Person, while the expression e.@Age finds all the XAttributes with the name Age. The Value property gets the first attribute in the collection and calls the Value property on that attribute. Summary .NET Language-Integrated Query adds query capabilities to the CLR and the languages that target it. The query facility builds on lambda expressions and expression trees to allow predicates,

projections, and key extraction expressions to be used as opaque executable code or as transparent in-memory data suitable for downstream processing or translation. The standard query operators defined by the LINQ project work over any IEnumerable<T>-based information source, and are integrated with ADO.NET (LINQ to SQL) and System.Xml (LINQ to XML) to allow relational and XML data to gain the benefits of language-integrated query. Standard Query Operators in a Nutshell

Operator Where Select/SelectMany Take/Skip/ TakeWhile/SkipWhile Join/GroupJoin Concat

Description Restriction operator based on predicate function Projection operators based on selector function Partitioning operators based on position or predicate function Join operators based on key selector functions Concatenation operator

OrderBy/ThenBy/OrderByDescending/ThenByDe Sorting operators sorting in ascending or scending descending order based on optional key selector and comparer functions Reverse GroupBy Distinct Union/Intersect Except AsEnumerable ToArray/ToList ToDictionary/ToLookup Sorting operator reversing the order of a sequence Grouping operator based on optional key selector and comparer functions Set operator removing duplicates Set operators returning set union or intersection Set operator returning set difference Conversion operator to IEnumerable<T> Conversion operator to array or List<T> Conversion operators to Dictionary<K,T> or Lookup<K,T> (multidictionary) based on key selector function Conversion operators to IEnumerable<T> based on filtering by or conversion to type argument Equality operator checking pairwise element equality

OfType/Cast SequenceEqual

First/FirstOrDefault/Last/LastOrDefault/Single/Si Element operators returning initial/final/only ngleOrDefault element based on optional predicate function ElementAt/ElementAtOrDefault DefaultIfEmpty Range Repeat Empty Element operators returning element based on position Element operator replacing empty sequence with default-valued singleton sequence Generation operator returning numbers in a range Generation operator returning multiple occurrences of a given value Generation operator returning an empty sequence

Any/All Contains Count/LongCount Sum/Min/Max/Average Aggregate

Quantifier checking for existential or universal satisfaction of predicate function Quantifier checking for presence of a given element Aggregate operators counting elements based on optional predicate function Aggregate operators based on optional selector functions Aggregate operator accumulating multiple values based on accumulation function and optional seed

Linq to SQL
Introduction Most programs written today manipulate data in one way or another and often this data is stored in a relational database. Yet there is a huge divide between modern programming languages and databases in how they represent and manipulate information. This impedance mismatch is visible in multiple ways. Most notable is that programming languages access information in databases through APIs that require queries to be specified as text strings. These queries are significant portions of the program logic. Yet they are opaque to the language, unable to benefit from compile-time verification and design-time features like IntelliSense. Of course, the differences go far deeper than that. How information is representedthe data modelis quite different between the two. Modern programming languages define information in the form of objects. Relational databases use rows. Objects have unique identity as each instance is physically different from another. Rows are identified by primary key values. Objects have references that identify and link instances together. Rows are left intentionally distinct requiring related rows to be tied together loosely using foreign keys. Objects stand alone, existing as long as they are still referenced by another object. Rows exist as elements of tables, vanishing as soon as they are removed. It is no wonder that applications expected to bridge this gap are difficult to build and maintain. It would certainly simplify the equation to get rid of one side or the other. Yet relational databases provide critical infrastructure for long-term storage and query processing, and modern programming languages are indispensable for agile development and rich computation. Until now, it has been the job of the application developer to resolve this mismatch in each application separately. The best solutions so far have been elaborate database abstraction layers that ferry the information between the applications domain-specific object models and the tabular representation of the database, reshaping and reformatting the data each way. Yet by obscuring the true data source, these solutions end up throwing away the most compelling feature of relational databases; the ability for the data to be queried. LINQ to SQL, a component of Visual Studio Code Name "Orcas", provides a run-time infrastructure for managing relational data as objects without losing the ability to query. It does this by translating language-integrated queries into SQL for execution by the database, and then translating the tabular results back into objects you define. Your application is then free to manipulate the objects while LINQ to SQL stays in the background tracking your changes automatically. LINQ to SQL is designed to be non-intrusive to your application. It is possible to migrate current ADO.NET solutions to LINQ to SQL in a piecemeal fashion (sharing the same connections and transactions) since LINQ to SQL is simply

another component in the ADO.NET family. LINQ to SQL also has extensive support for stored procedures, allowing reuse of the existing enterprise assets. LINQ to SQL applications are easy to get started. Objects linked to relational data can be defined just like normal objects, only decorated with attributes to identify how properties correspond to columns. Of course, it is not even necessary to do this by hand. A design-time tool is provided to automate translating pre-existing relational database schemas into object definitions for you. Together, the LINQ to SQL run-time infrastructure and design-time tools significantly reduce the workload for the database application developer. The following chapters provide an overview of how LINQ to SQL can be used to perform common database-related tasks. It is assumed that the reader is familiar with Language-Integrated Query and the standard query operators. LINQ to SQL is language-agnostic. Any language built to provide Language-Integrated Query can use it to enable access to information stored in relational databases. The samples in this document are shown in both C# and Visual Basic; LINQ to SQL can be used with the LINQ-enabled version of the Visual Basic compiler as well. A Quick Tour The first step in building a LINQ to SQL application is declaring the object classes you will use to represent your application data. Let's walk through an example. Creating Entity Classes We will start with a simple class Customer and associate it with the customers table in the Northwind sample database. To do this, we need only apply a custom attribute to the top of the class declaration. LINQ to SQL defines the Table attribute for this purpose. C# [Table(Name="Customers")] public class Customer { public string CustomerID; public string City; } Visual Basic <Table(Name:="Customers")> _ Public Class Customer Public CustomerID As String Public City As String End Class The Table attribute has a Name property that you can use to specify the exact name of the database table. If no Name property is supplied, LINQ to SQL will assume the database table has the same name as the class. Only instances of classes declared as tables will be stored in the database. Instances of these types of classes are known as entities. The classes themselves are known as entity classes. In addition to associating classes to tables you will need to denote each field or property you intend to associate with a database column. For this, LINQ to SQL defines the Column attribute. C# [Table(Name="Customers")] public class Customer { [Column(IsPrimaryKey=true)] public string CustomerID;

} Visual Basic

[Column] public string City;

<Table(Name:="Customers")> _ Public Class Customer <Column(IsPrimaryKey:=true)> _ Public CustomerID As String <Column> _ Public City As String End Class The Column attribute has a variety of properties you can use to customize the exact mapping between your fields and the database columns. One property of note is the Id property. It tells LINQ to SQL that the database column is part of the primary key in the table. As with the Table attribute, you only need to supply information in the Column attribute if it differs from what can be deduced from your field or property declaration. In this example, you need to tell LINQ to SQL that the CustomerID field is part of the primary key in the table, yet you don't have to specify the exact name or type. Only fields and properties declared as columns will be persisted to or retrieved from the database. Others will be considered as transient parts of your application logic. The DataContext The DataContext is the main conduit by which you retrieve objects from the database and resubmit changes. You use it in the same way that you would use an ADO.NET Connection. In fact, the DataContext is initialized with a connection or connection string you supply. The purpose of the DataContext is to translate your requests for objects into SQL queries made against the database and then assemble objects out of the results. The DataContext enables languageintegrated queryby implementing the same operator pattern as the standard query operators such as Where and Select. For example, you can use the DataContext to retrieve customer objects whose city is London as follows: C# // DataContext takes a connection string DataContext db = new DataContext("c:\\northwind\\northwnd.mdf"); // Get a typed table to run queries Table<Customer> Customers = db.GetTable<Customer>(); // Query for customers from London var q = from c in Customers where c.City == "London" select c; foreach (var cust in q) Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City); Visual Basic ' DataContext takes a connection string Dim db As DataContext = New DataContext("c:\northwind\northwnd.mdf") ' Get a typed table to run queries Dim Customers As Customers(Of Customer) = db.GetTable(Of Customer)() ' Query for customers from London Dim londonCustomers = From customer in Customers _

Where customer.City = "London" _ Select customer For Each cust in londonCustomers Console.WriteLine("id = " & cust.CustomerID & ", City = " & cust.City) Next Each database table is represented as a Table collection, accessible via the GetTable() method using its entity class to identify it. It is recommended that you declare a strongly typed DataContext instead of relying on the basic DataContext class and the GetTable() method. A strongly typed DataContext declares allTable collections as members of the context. C# public partial class Northwind : DataContext { public Table<Customer> Customers; public Table<Order> Orders; public Northwind(string connection): base(connection) {} } Visual Basic Partial Public Class Northwind Inherits DataContext Public Customers As Table(Of Customers) Public Orders As Table(Of Orders) Public Sub New(ByVal connection As String) MyBase.New(connection) End Sub End Class The query for customers from London can then be expressed more simply as: C# Northwind db = new Northwind("c:\\northwind\\northwnd.mdf"); var q = from c in db.Customers where c.City == "London" select c; foreach (var cust in q) Console.WriteLine("id = {0}, City = {1}",cust.CustomerID, cust.City); Visual Basic Dim db = New Northwind("c:\northwind\northwnd.mdf") Dim londonCustomers = From cust In db.Customers _ Where cust.City = "London" _ Select cust For Each cust in londonCustomers Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City) Next We will continue to use the strongly typed Northwind class for the remainder of the overview document. Defining Relationships Relationships in relational databases are typically modeled as foreign key values referring to primary keys in other tables. To navigate between them, you must explicitly bring the two tables together using a relational join operation. Objects, on the other hand, refer to each other using property references or collections of references navigated using "dot" notation. Obviously, dotting is simpler than joining, since you need not recall the explicit join condition each time you navigate.

For data relationships such as these that will always be the same, it becomes quite convenient to encode them as property references in your entity class. LINQ to SQL defines an Association attribute you can apply to a member used to represent a relationship. An association relationship is one like a foreign-key to primary-key relationship that is made by matching column values between tables. C# [Table(Name="Customers")] public class Customer { [Column(Id=true)] public string CustomerID; ... private EntitySet<Order> _Orders; [Association(Storage="_Orders", OtherKey="CustomerID")] public EntitySet<Order> Orders { get { return this._Orders; } set { this._Orders.Assign(value); } } } Visual Basic <Table(Name:="Customers")> _ Public Class Customer <Column(Id:=true)> _ Public CustomerID As String ... Private _Orders As EntitySet(Of Order) <Association(Storage:="_Orders", OtherKey:="CustomerID")> _ Public Property Orders() As EntitySet(Of Order) Get Return Me._Orders End Get Set(ByVal value As EntitySet(Of Order)) End Set End Property End Class The Customer class now has a property that declares the relationship between customers and their orders. The Orders property is of type EntitySet because the relationship is one-to-many. We use the OtherKey property in the Association attribute to describe how this association is done. It specifies the names of the properties in the related class to be compared with this one. There was also a ThisKey property we did not specify. Normally, we would use it to list the members on this side of the relationship. However, by omitting it we allow LINQ to SQL to infer them from the members that make up the primary key. Notice how this is reversed in the definition for the Order class. C# [Table(Name="Orders")] public class Order { [Column(Id=true)] public int OrderID; [Column] public string CustomerID; private EntityRef<Customer> _Customer; [Association(Storage="_Customer", ThisKey="CustomerID")]

} Visual Basic

public Customer Customer { get { return this._Customer.Entity; } set { this._Customer.Entity = value; } }

<Table(Name:="Orders")> _ Public Class Order <Column(Id:=true)> _ Public OrderID As String <Column> _ Public CustomerID As String Private _Customer As EntityRef(Of Customer) <Association(Storage:="_Customer", ThisKey:="CustomerID")> _ Public Property Customer() As Customer Get Return Me._Customer.Entity End Get Set(ByVal value As Customer) Me._Customers.Entity = value End Set End Property End Class The Order class uses the EntityRef type to describe the relationship back to the customer. The use of the EntityRef class is required to support deferred loading(discussed later). The Association attribute for the Customer property specifies the ThisKey property since the non-inferable members are now on this side of the relationship. Also take a look at the Storage property. It tells LINQ to SQL which private member is used to hold the value of the property. This allows LINQ to SQL to bypass your public property accessors when it stores and retrieves their value. This is essential if you want LINQ to SQL to avoid any custom business logic written into your accessors. If the storage property is not specified, the public accessors will be used instead. You may use the Storage property with Column attributes as well. Once you introduce relationships in your entity classes, the amount of code you need to write grows as you introduce support for notifications and graph consistency. Fortunately, there is a tool (described later) that can be used to generate all the necessary definitions as partial classes, allowing you to use a mix of generated code and custom business logic. For the rest of this document, we assume the tool has been used to generate a complete Northwind data context and all entity classes. Querying Across Relationships Now that you have relationships, you can use them when you write queries simply by referring to the relationship properties defined in your class. C# var q = from c in db.Customers from o in c.Orders where c.City == "London" select new { c, o }; Visual Basic Dim londonCustOrders = From cust In db.Customers, ord In cust.Orders _ Where cust.City = "London" _ Select Customer = cust, Order = ord

The above query uses the Orders property to form the cross product between customers and orders, producing a new sequence of Customer and Order pairs. It's also possible to do the reverse. C# var q = from o in db.Orders where o.Customer.City == "London" select new { c = o.Customer, o }; Visual Basic Dim londonCustOrders = From ord In db.Orders _ Where ord.Customer.City = "London" _ Select Customer = ord.Customer, Order = ord In this example, the orders are queried and the Customer relationship is used to access information on the associated Customer object. Modifying and Saving Entities Few applications are built with only query in mind. Data must be created and modified, too. LINQ to SQL is designed to offer maximum flexibility in manipulating and persisting changes made to your objects. As soon as entity objects are availableeither by retrieving them through a query or constructing them anewyou may manipulate them as normal objects in your application, changing their values or adding and removing them from collections as you see fit. LINQ to SQL tracks all your changes and is ready to transmit them back to the database as soon as you are done. The example below uses the Customer and Order classes generated by a tool from the metadata of the entire Northwind sample database. The class definitions have not been shown for brevity. C# Northwind db = new Northwind("c:\\northwind\\northwnd.mdf"); // Query for a specific customer string id = "ALFKI"; var cust = db.Customers.Single(c => c.CustomerID == id); // Change the name of the contact cust.ContactName = "New Contact"; // Create and add a new Order to Orders collection Order ord = new Order { OrderDate = DateTime.Now }; cust.Orders.Add(ord); // Ask the DataContext to save all the changes db.SubmitChanges(); Visual Basic Dim db As New Northwind("c:\northwind\northwnd.mdf") ' Query for a specific customer Dim id As String = "ALFKI" Dim targetCustomer = (From cust In db.Customers _ Where cust.CustomerID = id).First ' Change the name of the contact targetCustomer.ContactName = "New Contact" ' Create and add a new Order to Orders collection Dim id = New Order With { .OrderDate = DateTime.Now } targetCustomer.Orders.Add(ord) ' Ask the DataContext to save all the changes db.SubmitChanges() When SubmitChanges() is called, LINQ to SQL automatically generates and executes SQL commands in order to transmit the changes back to the database. It is also possible to override this behavior with custom logic. The custom logic may call a database stored procedure.

Queries In-Depth LINQ to SQL provides an implementation of the standard query operators for objects associated with tables in a relational database. This chapter describes the LINQ to SQL-specific aspects of queries. Query Execution Whether you write a query as a high-level query expression or build one out of the individual operators, the query that you write is not an imperative statement executed immediately. It is a description. For example, in the declaration below the local variable q refers to the description of the query not the result of executing it. C# var q = from c in db.Customers where c.City == "London" select c; foreach (Customer c in q) Console.WriteLine(c.CompanyName); Visual Basic Dim londonCustomers = From cust In db.Customers _ where cust.City = "London" For Each cust In londonCustomers Console.WriteLine(cust.CompanyName) Next The actual type of q in this instance is IQueryable<Customer>. It's not until the application attempts to enumerate the contents of the query that it actually executes. In this example the foreach statement causes the execution to occur. An IQueryable object is similar to an ADO.NET command object. Having one in hand does not imply that a query was executed. A command object holds onto a string that describes a query. Likewise, an IQueryable object holds onto a description of a query encoded as a data structure known as an Expression. A command object has an ExecuteReader() method that causes execution, returning results as a DataReader. An IQueryable object has a GetEnumerator() method that causes the execution, returning results as an IEnumerator<Customer>. Therefore, it follows that if a query is enumerated twice it will be executed twice. C# var q = from c in db.Customers where c.City == "London" select c; // Execute first time foreach (Customer c in q) Console.WriteLine(c.CompanyName); // Execute second time foreach (Customer c in q) Console.WriteLine(c.CompanyName); Visual Basic Dim londonCustomers = From cust In db.Customers _ where cust.City = "London" ' Execute first time For Each cust In londonCustomers Console.WriteLine(cust.CompanyName) Next

' Execute second time For Each cust In londonCustomers Console.WriteLine(cust.CustomerID) Next This behavior is known as deferred execution. Just like with an ADO.NET command object it is possible to hold onto a query and re-execute it. Of course, application writers often need to be very explicit about where and when a query is executed. It would be unexpected if an application were to execute a query multiple times simply because it needed to examine the results more than once. For example, you may want to bind the results of a query to something like a DataGrid. The control may enumerate the results each time it paints on the screen. To avoid executing multiple times convert the results into any number of standard collection classes. It is easy to convert the results into a list or array using the standard query operators ToList() or ToArray(). C# var q = from c in db.Customers where c.City == "London" select c; // Execute once using ToList() or ToArray() var list = q.ToList(); foreach (Customer c in list) Console.WriteLine(c.CompanyName); foreach (Customer c in list) Console.WriteLine(c.CompanyName); Visual Basic Dim londonCustomers = From cust In db.Customers _ where cust.City = "London" ' Execute once using ToList() or ToArray() Dim londonCustList = londonCustomers.ToList() ' Neither of these iterations re-executes the query For Each cust In londonCustList Console.WriteLine(cust.CompanyName) Next For Each cust In londonCustList Console.WriteLine(cust.CompanyName) Next One benefit of deferred execution is that queries may be piecewise constructed with execution only occurring when the construction is complete. You can start out composing a portion of a query, assigning it to a local variable and then sometime later continue applying more operators to it. C# var q = from c in db.Customers where c.City == "London" select c; if (orderByLocation) { q= from c in q orderby c.Country, c.City select c; } else if (orderByName) {

q= from c in q orderby c.ContactName select c;

} foreach (Customer c in q) Console.WriteLine(c.CompanyName); Visual Basic Dim londonCustomers = From cust In db.Customers _ where cust.City = "London" if orderByLocation Then londonCustomers = From cust in londonCustomers _ Order By cust.Country, cust.City Else If orderByName Then londonCustomers = From cust in londonCustomers _ Order By cust.ContactName End If For Each cust In londonCustList Console.WriteLine(cust.CompanyName) Next In this example, q starts out as a query for all customers in London. Later on it changes into an ordered query depending on application state. By deferring execution the query can be constructed to suit the exact needs of the application without requiring risky string manipulation. Object Identity Objects in the runtime have unique identity. If two variables refer to the same object, they are actually referring to the same object instance. Because of this, changes made via a path through one variable are immediately visible through the other. Rows in a relational database table do not have unique identity. However, they do have a primary key and that primary key may be unique, meaning no two rows may share the same key. Yet this only constrains the contents of the database table. Therefore, as long as we only interact with the data through remote commands, it amounts to about the same thing. However, this is rarely the case. Most often data is brought out of the database and into a different tier where an application manipulates it. Clearly, this is the model that LINQ to SQL is designed to support. When the data is brought out of the database as rows, there is no expectation that two rows representing the same data actually correspond to the same row instances. If you query for a specific customer twice, you get two rows of data, each containing the same information. Yet with objects, you expect something quite different. You expect that if you ask the DataContext for the same information again, it will in fact give you back the same object instance. You expect this because objects have special meaning for your application and you expect them to behave like normal objects. You designed them as hierarchies or graphs and you certainly expect to retrieve them as such, without hordes of replicated instances merely because you asked for the same thing twice. Because of this, the DataContext manages object identity. Whenever a new row is retrieved from the database, it is logged in an identity table by its primary key and a new object is created. Whenever that same row is retrieved again, the original object instance is handed back to the application. In this way, the DataContexttranslates the databases concept of identity (keys) into the languages concept (instances). The application only ever sees the object in the state that it was first retrieved. The new data, if different, is thrown away. You might be puzzled by this, since why would any application throw data away? As it turns out this is how LINQ to SQL manages integrity of the local objects and is able to support optimistic updates. Since the only changes that occur after the object is initially created are those made by the application, the intent of the application is clear. If changes by an outside party have occurred

in the interim they will be identified at the time SubmitChanges() is called. More of this is explained in the Simultaneous Changes section. Note that, in the case that the database contains a table without a primary key, LINQ to SQL allows queries to be submitted over the table, but it doesn't allow updates. This is because the framework cannot identify which row to update given the lack of a unique key. Of course, if the object requested by the query is easily identifiable by its primary key as one already retrieved no query is executed at all. The identity table acts as a cache storing all previously retrieved objects. Relationships As we saw in the quick tour, references to other objects or collections of other objects in your class definitions directly correspond to foreign-key relationships in the database. You can use these relationships when you query by simply using dot notation to access the relationship properties, navigating from one object to another. These access operations translate to more complicated joins or correlated sub-queries in the equivalent SQL, allowing you to walk through your object graph during a query. For example, the following query navigates from orders to customers as a way to restrict the results to only those orders for customers located in London. C# var q = from o in db.Orders where o.Customer.City == "London" select o; Visual Basic Dim londonOrders = From ord In db.Orders _ where ord.Customer.City = "London" If relationship properties did not exist you would have to write them out manually as joins just as you would do in a SQL query. C# var q = from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID where c.City == "London" select o; Visual Basic Dim londonOrders = From cust In db.Customers _ Join ord In db.Orders _ On cust.CustomerID Equals ord.CustomerID _ Where ord.Customer.City = "London" _ Select ord The relationship property allows you to define this particular relationship once enabling the use of the more convenient dot syntax. However, this is not the reason why relationship properties exist. They exist because we tend to define our domain-specific object models as hierarchies or graphs. The objects we choose to program against have references to other objects. It's only a happy coincidence that since object-to-object relationships correspond to foreign key style relationships in databases that property access leads to a convenient way to write joins.

Therefore, the existence of relationship properties is more important on the results side of a query than as part of the query itself. Once you have your hands on a particular customer, its class definition tells you that customers have orders. So when you look into the Orders property of a particular customer you expect to see the collection populated with all the customer's orders, since that is in fact the contract you declared by defining the classes this way. You expect to see the orders there even if you did not particularly ask for orders up front. You expect your object model to maintain an illusion that it is an in-memory extension of the database, with related objects immediately available. LINQ to SQL implements a technique called deferred loading in order to help maintain this illusion. When you query for an object you actually only retrieve the objects you asked for. The related objects are not automatically fetched at the same time. However, the fact that the related objects are not already loaded is not observable since as soon as you attempt to access them a request goes out to retrieve them. C# var q = from o in db.Orders where o.ShipVia == 3 select o; foreach (Order o in q) { if (o.Freight > 200) SendCustomerNotification(o.Customer); ProcessOrder(o); } Visual Basic Dim shippedOrders = From ord In db.Orders _ where ord.ShipVia = 3 For Each ord In shippedOrders If ord.Freight > 200 Then SendCustomerNotification(ord.Customer) ProcessOrder(ord) End If Next For example, you may want to query for a particular set of orders and then only occasionally send an email notification to particular customers. You would not necessary need to retrieve all customer data up front with every order. Deferred loading allows you to defer the cost of retrieving extra information until you absolutely have to. Of course, the opposite might also be true. You might have an application that needs to look at customer and order data at the same time. You know you need both sets of data. You know your application is going to drill down through each customer's orders as soon as you get them. It would be unfortunate to fire off individual queries for orders for every customer. What you really want to happen is to have the order data retrieved together with the customers. C# var q = from c in db.Customers where c.City == "London" select c; foreach (Customer c in q) { foreach (Order o in c.Orders) { ProcessCustomerOrder(o); } } Visual Basic Dim londonCustomers = From cust In db.Customer _ Where cust.City = "London"

For Each cust In londonCustomers For Each ord In cust.Orders ProcessCustomerOrder(ord) End If Next Certainly, you can always find a way to join customers and orders together in a query by forming the cross product and retrieving all the relative bits of data as one big projection. But then the results would not be entities. Entities are objects with identity that you can modify while the results would be projections that cannot be changed and persisted. Worse, you would be retrieving a huge amount of redundant data as each customer repeats for each order in the flattened join output. What you really need is a way to retrieve a set of related objects at the same timea delineated portion of a graph so you would never be retrieving any more or any less than was necessary for your intended use. LINQ to SQL allows you to request immediate loading of a region of your object model for just this reason. It does this by allowing the specification of a DataShapefor a DataContext. The DataShape class is used to instruct the framework about which objects to retrieve when a particular type is retrieved. This is accomplished by using the LoadWith method as in the following: C# DataShape ds = new DataShape(); ds.LoadWith<Customer>(c => c.Orders); db.Shape = ds; var q = from c in db.Customers where c.City == "London" select c; Visual Basic Dim ds As DataShape = New DataShape() ds.LoadWith(Of Customer)(Function(c As Customer) c.Orders) db.Shape = ds Dim londonCustomers = From cust In db.Customers _ Where cust.City = "London" _ Select cust In the previous query, all the Orders for all the Customers who live in London are retrieved when the query is executed, so that successive access to the Ordersproperty on a Customer object doesn't trigger a database query. The DataShape class can also be used to specify sub-queries that are applied to a relationship navigation. For example, if you want to retrieve just the Orders that have been shipped today, you can use the AssociateWith method on the DataShape as in the following: C# DataShape ds = new DataShape(); ds.AssociateWith<Customer>( c => c.Orders.Where(p => p.ShippedDate != DateTime.Today)); db.Shape = ds; var q = from c in db.Customers where c.City == "London" select c; foreach(Customer c in q) { foreach(Order o in c.Orders) {} } Visual Basic

Dim ds As DataShape = New DataShape() ds.AssociateWith(Of Customer)( _ Function(cust As Customer) From cust In db.Customers _ Where order.ShippedDate <> Today _ Select cust) db.Shape = ds Dim londonCustomers = From cust In db.Customers _ Where cust.City = "London" _ Select cust For Each cust in londonCustomers For Each ord In cust.Orders Next Next In the previous code, the inner foreach statement iterates just over the Orders that have been shipped today, because just such orders have been retrieved from the database. It is important to notice two facts about the DataShape class:

1. After assigning a DataShape to a DataContext, the DataShape cannot be modified. 2.


Any LoadWith or AssociateWith method call on such a DataShape will return an error at run time. It is impossible to create cycles by using LoadWith or AssociateWith. For example, the following generates an error at run time: C# DataShape ds = new DataShape(); ds.AssociateWith<Customer>( c=>c.Orders.Where(o=> o.Customer.Orders.Count() < 35); Visual Basic Dim ds As DataShape = New DataShape() ds.AssociateWith(Of Customer)( _ Function(cust As Customer) From ord In cust.Orders _ Where ord.Customer.Orders.Count() < 35) Joins Most queries against object models heavily rely on navigating object references in the object model. However, there are interesting "relationships" between entities that may not be captured in the object model as references. For example Customer.Orders is a useful relationship based on foreign key relationships in the Northwind database. However, Suppliers and Customers in the same City or Country is an ad hoc relationship that is not based on a foreign key relationship and may not be captured in the object model. Joins provide an additional mechanism to handle such relationships. LINQ to SQL supports the new join operators introduced in LINQ. Consider the following problemfind suppliers and customers based in the same city. The following query returns supplier and customer company names and the common city as a flattened result. This is the equivalent of the inner equi-join in relational databases: C# var q = from s in db.Suppliers join c in db.Customers on s.City equals c.City select new { Supplier = s.CompanyName, Customer = c.CompanyName, City = c.City }; Visual Basic

Dim customerSuppliers = From sup In db.Suppliers _ Join cust In db.Customers _ On sup.City Equals cust.City _ Select Supplier = sup.CompanyName, _ CustomerName = cust.CompanyName, _ City = cust.City The above query eliminates suppliers that are not in the same city as a certain customer. However, there are times when we don't want to eliminate one of the entities in an ad hoc relationship. The following query lists all suppliers with groups of customers for each of the suppliers. If a particular supplier does not have any customer in the same city, the result is an empty collection of customers corresponding to that supplier. Note that the results are not flat each supplier has an associated collection. Effectively, this provides group joinit joins two sequences and groups elements of the second sequence by the elements of the first sequence. C# var q = from s in db.Suppliers join c in db.Customers on s.City equals c.City into scusts select new { s, scusts }; Visual Basic Dim customerSuppliers = From sup In db.Suppliers _ Group Join cust In db.Customers _ On sup.City Equals cust.City _ Into supCusts _ Select Supplier = sup, _ Customers = supCusts Group join can be extended to multiple collections as well. The following query extends the above query by listing employees that are in the same city as the supplier. Here, the result shows a supplier with (possibly empty) collections of customers and employees. C# var q = from s in db.Suppliers join c in db.Customers on s.City equals c.City into scusts join e in db.Employees on s.City equals e.City into semps select new { s, scusts, semps }; Visual Basic Dim customerSuppliers = From sup In db.Suppliers _ Group Join cust In db.Customers _ On sup.City Equals cust.City _ Into supCusts _ Group Join emp In db.Employees _ On sup.City Equals emp.City _ Into supEmps _ Select Supplier = sup, _ Customers = supCusts, Employees = supEmps The results of a group join can also be flattened. The results of flattening the group join between suppliers and customers are multiple entries for suppliers with multiple customers in their city one per customer. Empty collections are replaced with nulls. This is equivalent to a left outer equijoin in relational databases. C# var q = from s in db.Suppliers join c in db.Customers on s.City equals c.City into sc from x in sc.DefaultIfEmpty() select new {

Supplier = s.CompanyName, Customer = x.CompanyName, City = x.City }; Visual Basic Dim customerSuppliers = From sup In db.Suppliers _ Group Join cust In db.Customers _ On sup.City Equals cust.City _ Into supCusts _ Select Supplier = sup, _ CustomerName = supCusts.CompanyName, sup.City The signatures for underlying join operators are defined in the standard query operators document. Only equi-joins are supported and the two operands ofequals must have the same type. Projections So far, we have only looked at queries for retrieving entitiesobjects directly associated with database tables. We need not constrain ourselves to just this. The beauty of a query language is that you can retrieve information in any form you want. You will not be able to take advantage of automatic change tracking or identity management when you do so. However, you can get just the data you want. For example, you may simply need to know the company names of all customers in London. If this is the case there is no particular reason to retrieve entire customer objects merely to pick out names. You can project out the names as part of the query. C# var q = from c in db.Customers where c.City == "London" select c.CompanyName; Visual Basic Dim londonCustomerNames = From cust In db.Customer _ Where cust.City = "London" _ Select cust.CompanyName In this case, q becomes a query that retrieves a sequence of strings. If you want to get back more than just a single name, but not enough to justify fetching the entire customer object, you can specify any subset you want by constructing the results as part of your query. C# var q = from c in db.Customers where c.City == "London" select new { c.CompanyName, c.Phone }; Visual Basic Dim londonCustomerInfo = From cust In db.Customer _ Where cust.City = "London" _ Select cust.CompanyName, cust.Phone This example uses an anonymous object initializer to create a structure that holds both the company name and phone number. You may not know what to call the type, but with implicitly typed local variable declaration in the language you do not necessarily need to. C# var q =

from c in db.Customers where c.City == "London" select new { c.CompanyName, c.Phone }; foreach(var c in q) Console.WriteLine("{0}, {1}", c.CompanyName, c.Phone); Visual Basic Dim londonCustomerInfo = From cust In db.Customer _ Where cust.City = "London" _ Select cust.CompanyName, cust.Phone For Each cust In londonCustomerInfo Console.WriteLine(cust.CompanyName & ", " & cust.Phone) Next If you are consuming the data immediately, anonymous types make a good alternative to explicitly defining classes to hold your query results. You can also form cross products of entire objects, though you might rarely have a reason to do so. C# var q = from c in db.Customers from o in c.Orders where c.City == "London" select new { c, o }; Visual Basic Dim londonOrders = From cust In db.Customer, _ ord In db.Orders _ Where cust.City = "London" _ Select Customer = cust, Order = ord This query constructs a sequence of pairs of customer and order objects. It's also possible to make projections at any stage of the query. You can project data into newly constructed objects and then refer to those objects' members in subsequent query operations. C# var q = from c in db.Customers where c.City == "London" select new {Name = c.ContactName, c.Phone} into x orderby x.Name select x; Visual Basic Dim londonItems = From cust In db.Customer _ Where cust.City = "London" _ Select Name = cust.ContactName, cust.Phone _ Order By Name Be wary of using parameterized constructors at this stage, though. It is technically valid to do so, yet it is impossible for LINQ to SQL to track how constructor usage affects member state without understanding the actual code inside the constructor. C# var q = from c in db.Customers where c.City == "London" select new MyType(c.ContactName, c.Phone) into x orderby x.Name select x; Visual Basic

Dim londonItems = From cust In db.Customer _ Where cust.City = "London" _ Select MyType = New MyType(cust.ContactName, cust.Phone) _ Order By MyType.Name Because LINQ to SQL attempts to translate the query into pure relational SQL locally defined object types are not available on the server to actually construct. All object construction is actually postponed until after the data is retrieved back from the database. In place of actual constructors, the generated SQL uses normal SQL column projection. Since it is not possible for the query translator to understand what is happening during a constructor call, it is unable to establish a meaning for the Name field of MyType. Instead, the best practice is to always use object initializers to encode projections. C# var q = from c in db.Customers where c.City == "London" select new MyType { Name = c.ContactName, HomePhone = c.Phone } into x orderby x.Name select x; Visual Basic Dim londonCustomers = From cust In db.Customer _ Where cust.City = "London" _ Select Contact = New With {.Name = cust.ContactName, _ .Phone = cust.Phone} _ Order By Contact.Name The only safe place to use a parameterized constructor is in the final projection of a query. C# var e = new XElement("results", from c in db.Customers where c.City == "London" select new XElement("customer", new XElement("name", c.ContactName), new XElement("phone", c.Phone) ) ); Visual Basic Dim x = <results> <%= From cust In db.Customers _ Where cust.City = "London" _ Select <customer> <name><%= cust.ContactName %></name> <phone><%= cust.Phone %></phone> </customer> %> </results> You can even use elaborate nesting of object constructors if you desire, like this example that constructs XML directly out of the result of a query. It works as long as it's the last projection of the query. Still, even if constructor calls are understood, calls to local methods may not be. If your final projection requires invocation of local methods, it is unlikely that LINQ to SQL will be able to oblige. Method calls that do not have a known translation into SQL cannot be used as part of the query. One exception to this rule is method calls that have no arguments dependent on query variables. These are not considered part of the translated query and instead are treated as parameters.

Still elaborate projections (transformations) may require local procedural logic to implement. For you to use your own local methods in a final projection you will need to project twice. The first projection extracts all the data values you'll need to reference and the second projection performs the transformation. In between these two projections is a call to the AsEnumerable() operator that shifts processing at that point from a LINQ to SQL query into a locally executed one. C# var q = from c in db.Customers where c.City == "London" select new { c.ContactName, c.Phone }; var q2 = from c in q.AsEnumerable() select new MyType { Name = DoNameProcessing(c.ContactName), Phone = DoPhoneProcessing(c.Phone) }; Visual Basic Dim londonCustomers = From cust In db.Customer _ Where cust.City = "London" _ Select cust.ContactName, cust.Phone Dim processedCustomers = From cust In londonCustomers.AsEnumerable() _ Select Contact = New With { _ .Name = DoNameProcessing(cust.ContactName), _ .Phone = DoPhoneProcessing(cust.Phone)} Note The AsEnumerable() operator, unlike ToList() and ToArray(), does not cause execution of the query. It is still deferred. The AsEnumerable()operator merely changes the static typing of the query, turning a IQueryable<T> (IQueryable (ofT) in Visual Basic) into an IEnumerable<T>(IEnumerable (ofT) in Visual Basic), tricking the compiler into treating the rest of the query as locally executed.

Compiled Queries It is common in many applications to execute structurally similar queries many times. In such cases, it is possible to increase performance by compiling the query once and executing it several times in the application with different parameters. This result is obtained in LINQ to SQL by using the CompiledQuery class. The following code shows how to define a compiled query: C# static class Queries { public static Func<Northwind, string, IQueryable<Customer>> CustomersByCity = CompiledQuery.Compile((Northwind db, string city) => from c in db.Customers where c.City == city select c); } Visual Basic Class Queries public Shared Function(Of Northwind, String, IQueryable(Of Customer)) _ CustomersByCity = CompiledQuery.Compile( _ Function(db As Northwind, city As String) _ From cust In db.Customers Where cust.City = city) End Class The Compile method returns a delegate that can be cached and executed afterward several times by just changing the input parameters. The following code shows an example of this:

C# public IEnumerable<Customer> GetCustomersByCity(string city) { Northwind db = new Northwind(); return Queries.CustomersByCity(myDb, city); } Visual Basic Public Function GetCustomersByCity(city As String) _ As IEnumerable(Of Customer) Dim db As Northwind = New Northwind() Return Queries.CustomersByCity(myDb, city) End Function SQL Translation LINQ to SQL does not actually execute queries; the relational database does. LINQ to SQL translates the queries you wrote into equivalent SQL queries and sends them to the server for processing. Because execution is deferred, LINQ to SQL is able to examine your entire query even if assembled from multiple parts. Since the relational database server is not actually executing IL (aside from the CLR integration in SQL Server 2005); the queries are not transmitted to the server as IL. They are in fact transmitted as parameterized SQL queries in text form. Of course, SQLeven T-SQL with CLR integrationis incapable of executing the variety of methods that are locally available to your program. Therefore the queries you write must be translated into equivalent operations and functions that are available inside the SQL environment. Most methods and operators on .Net Framework built-in types have direct translations into SQL. Some can be produced out of the functions that are available. The ones that cannot be translated are disallowed, generating run-time exceptions if you try to use them. There is a section later in the document that details the framework methods that are implemented to translate into SQL. The Entity Lifecycle LINQ to SQL is more than just an implementation of the standard query operators for relational databases. In addition to translating queries, it is a service that manages your objects throughout their lifetime, aiding you in maintaining the integrity of your data and automating the process of translating your modifications back into the store. In a typical scenario, objects are retrieved through one or more queries and then manipulated in some way or another until the application is ready to send the changes back to the server. This process may repeat a number of times until the application no longer has use for this information. At that point, the objects are reclaimed by the runtime just like normal objects. The data, however, remains in the database. Even after being erased from their run-time existence, objects representing the same data can still be retrieved. In this sense, the object's true lifetime exists beyond any single run-time manifestation. The focus of this chapter is the entity lifecycle where a cycle refers to the time span of a single manifestation of an entity object within a particular run-time context. The cycle starts when the DataContext becomes aware of a new instance and ends when the object or DataContext is no longer needed. Tracking Changes After entities are retrieved from the database, you are free to manipulate them as you like. They are your objects; use them as you will. As you do this, LINQ to SQL tracks changes so that it can persist them into the database when SubmitChanges() is called.

LINQ to SQL starts tracking your entities the moment they are retrieved from the database, before you ever lay your hands on them. Indeed, the identity management service discussed earlier has already kicked in as well. Change tracking costs very little in additional overhead until you actually start making changes. C# Customer cust = db.Customers.Single(c => c.CustomerID == "ALFKI"); cust.CompanyName = "Dr. Frogg's Croakers"; Visual Basic ' Query for a specific customer Dim id As String = "ALFKI" Dim targetCustomer = (From cust In db.Customers _ Where cust.CustomerID = id).First targetCustomer.CompanyName = "Dr. Frogg's Croakers" As soon as the CompanyName is assigned in the example above, LINQ to SQL becomes aware of the change and is able to record it. The original values of all data members are retained by the change tracking service. The change tracking service also records all manipulations of relationship properties. You use relationship properties to establish the links between your entities, even though they may be linked by key values in the database. There is no need to directly modify the members associated with the key columns. LINQ to SQL automatically synchronizes them for you before the changes are submitted. C# Customer cust1 = db.Customers.Single(c => c.CustomerID == custId1); foreach (Order o in db.Orders.Where(o => o.CustomerID == custId2)) { o.Customer = cust1; } Visual Basic Dim targetCustomer = (From cust In db.Customers _ Where cust.CustomerID = custId1).First For Each ord In (From o In db.Orders _ Where o.CustomerID = custId2) o.Customer = targetCustomer Next You can move orders from one customer to another by simply making an assignment to their Customer property. Since the relationship exists between the customer and the order, you can change the relationship by modifying either side. You could have just as easily removed them from the Orders collection of cust2and added them to the orders collection of cust1, as shown below. C# Customer cust1 = db.Customers.Single(c => c.CustomerID == custId1); Customer cust2 = db.Customers.Single(c => c.CustomerID == custId2); // Pick some order Order o = cust2.Orders[0]; // Remove from one, add to the other cust2.Orders.Remove(o); cust1.Orders.Add(o); // Displays 'true' Console.WriteLine(o.Customer == cust1); Visual Basic Dim targetCustomer1 = (From cust In db.Customers _ Where cust.CustomerID = custId1).First Dim targetCustomer2 = (From cust In db.Customers _

Where cust.CustomerID = custId1).First ' Pick some order Dim o As Order = targetCustomer2.Orders(0) ' Remove from one, add to the other targetCustomer2.Orders.Remove(o) targetCustomer1.Orders.Add(o) ' Displays 'True' MsgBox(o.Customer = targetCustomer1) Of course, if you assign a relationship the value of null, you are in fact getting rid of the relationship completely. Assigning a Customer property of an order tonull actually removes the order from the customer's list. C# Customer cust = db.Customers.Single(c => c.CustomerID == custId1); // Pick some order Order o = cust.Orders[0]; // Assign null value o.Customer = null; // Displays 'false' Console.WriteLine(cust.Orders.Contains(o)); Visual Basic Dim targetCustomer = (From cust In db.Customers _ Where cust.CustomerID = custId1).First ' Pick some order Dim o As Order = targetCustomer.Orders(0) ' Assign null value o.Customer = Nothing ' Displays 'False' Msgbox(targetCustomer.Orders.Contains(o)) Automatic updating of both sides of a relationship is essential for maintaining consistency of your object graph. Unlike normal objects, relationships between data are often bidirectional. LINQ to SQL allows you to use properties to represent relationships. However, it does not offer a service to automatically keep these bidirectional properties in sync. This is a level of service that must be baked directly into your class definitions. Entity classes generated using the code generation tool have this capability. In the next chapter, we will show you how to do this to your own handwritten classes. It is important to note, however, that removing a relationship does not imply that an object has been deleted from the database. Remember, the lifetime of the underlying data persists in the database until the row has been deleted from the table. The only way to actually delete an object is to remove it from its Tablecollection. C# Customer cust = db.Customers.Single(c => c.CustomerID == custId1); // Pick some order Order o = cust.Orders[0]; // Remove it directly from the table (I want it gone!) db.Orders.Remove(o); // Displays 'false'.. gone from customer's Orders Console.WriteLine(cust.Orders.Contains(o)); // Displays 'true'.. order is detached from its customer Console.WriteLine(o.Customer == null); Visual Basic Dim targetCustomer = (From cust In db.Customers _ Where cust.CustomerID = custId1).First ' Pick some order Dim o As Order = targetCustomer.Orders(0)

' Remove it directly from the table (I want it gone!) db.Orders.Remove(o) ' Displays 'False'.. gone from customers Orders Msgbox(targetCustomer.Orders.Contains(o)) ' Displays 'True'.. order is detached from its customer Msgbox(o.Customer = Nothing) Like with all other changes, the order has not actually been deleted. It just looks that way to us since it has been removed and detached from the rest of our objects. When the order object was removed from the Orders table, it was marked for deletion by the change tracking service. The actually deletion from the database will occur when the changes are submitted on a call to SubmitChanges(). Note that the object itself is never deleted. The runtime manages the lifetime of object instances, so it sticks around as long as you are still holding a reference to it. However, after an object has been removed from its Table and changes submitted it is no longer tracked by the change tracking service. The only other time an entity is left untracked is when it exists before the DataContext is aware of it. This happens whenever you create new objects in your code. You are free to use instances of entity classes in your application without ever retrieving them from a database. Change tacking and identity management only apply to those objects that the DataContext is aware of. Therefore neither service is enabled for newly created instances until you add them to the DataContext. This can occur in one of two ways. You can call the Add() method on the related Table collection manually. C# Customer cust = new Customer { CustomerID = "ABCDE", ContactName = "Frond Smooty", CompanyTitle = "Eggbert's Eduware", Phone = "888-925-6000" }; // Add new customer to Customers table db.Customers.Add(cust); Visual Basic Dim targetCustomer = New Customer With { _ .CustomerID = ABCDE, _ .ContactName = Frond Smooty, _ .CompanyTitle = Eggberts Eduware, _ .Phone = 888-925-6000} ' Add new customer to Customers table db.Customers.Add(cust) Alternatively, you can attach a new instance to an object that the DataContext is already aware of. C# // Add an order to a customer's Orders cust.Orders.Add( new Order { OrderDate = DateTime.Now } ); Visual Basic ' Add an order to a customer's Orders targetCustomer.Orders.Add( _ New Order With { .OrderDate = DateTime.Now } ) The DataContext will discover your new object instances even if they are attached to other new instances. C#

// Add an order and details to a customer's Orders Cust.Orders.Add( new Order { OrderDate = DateTime.Now, OrderDetails = { new OrderDetail { Quantity = 1, UnitPrice = 1.25M, Product = someProduct } } } ); Visual Basic ' Add an order and details to a customer's Orders targetCustomer.Orders.Add( _ New Order With { _ .OrderDate = DateTime.Now, _ .OrderDetails = New OrderDetail With { _ .Quantity = 1, .UnitPrice = 1.25M, .Product = someProduct } }) Basically, the DataContext will recognize any entity in your object graph that is not currently tracked as a new instance, whether or not you called the Add()method. Using a read-only DataContext Many scenarios don't necessitate updating the entities retrieved from the database. Showing a table of Customers on a Web page is one obvious example. In all such cases, it is possible to improve performance by instructing the DataContext not to track the changes to the entities. This is achieved by specifying theObjectTracking property on the DataContext to be false as in the following code: C# db.ObjectTracking = false; var q = db.Customers.Where( c => c.City = "London"); foreach(Customer c in q) Display(c); Visual Basic db.ObjectTracking = False Dim londonCustomers = From cust In db.Customer _ Where cust.City = "London" For Each c in londonCustomers Display(c) Next Submitting Changes Regardless of how many changes you make to your objects, those changes were only made to inmemory replicas. Nothing has yet happened to the actual data in the database. Transmission of this information to the server will not happen until you explicitly request it by calling SubmitChanges() on the DataContext. C#

Northwind db = new Northwind("c:\\northwind\\northwnd.mdf"); // make changes here db.SubmitChanges(); Visual Basic Dim db As New Northwind("c:\northwind\northwnd.mdf") ' make changes here db.SubmitChanges() When you do call SubmitChanges(), the DataContext will attempt to translate all your changes into equivalent SQL commands, inserting, updating, or deleting rows in corresponding tables. These actions can be overridden by your own custom logic if you desire, however the order of submission is orchestrated by a service of the DataContext known as the change processor. The first thing that happens when you call SubmitChanges() is that the set of known objects are examined to determine if new instances have been attached to them. These new instances are added to the set of tracked objects. Next, all objects with pending changes are ordered into a sequence of objects based on dependencies between them. Those objects whose changes depend on other objects are sequenced after their dependencies. Foreign key constraints and uniqueness constraints in the database play a big part in determining the correct ordering of changes. Then, just before any actual changes are transmitted, a transaction is started to encapsulate the series of individual commands unless one is already in scope. Finally, one by one the changes to the objects are translated into SQL commands and sent to the server. At this point, any errors detected by the database will cause the submission process to abort and an exception will be raised. All changes to the database will be rolled back as if none of the submissions ever took place. The DataContext will still have a full recording of all changes so it is possible to attempt to rectify the problem and resubmit them by calling SubmitChanges() again. C# Northwind db = new Northwind("c:\\northwind\\northwnd.mdf"); // make changes here try { db.SubmitChanges(); } catch (Exception e) { // make some adjustments ... // try again db.SubmitChanges(); } Visual Basic Dim db As New Northwind("c:\northwind\northwnd.mdf") ' make changes here Try db.SubmitChanges() Catch e As Exception ' make some adjustments ... ' try again db.SubmitChanges() End Try When the transaction around the submission completes successfully, the DataContext will accept the changes to the objects by simply forgetting the change tracking information. Simultaneous Changes There are a variety of reasons why a call to SubmitChanges() may fail. You may have created an object with an invalid primary key; one that's already in use, or with a value that violates some check constraint of the database. These kinds of checks are difficult to bake into business logic

since they often require absolute knowledge of the entire database state. However, the most likely reason for failure is simply that someone else made changes to the objects before you. Certainly, this would be impossible if you were locking each object in the database and using a fully serialized transaction. However, this style of programming (pessimistic concurrency) is rarely used since it is expensive and true clashes seldom occur. The most popular form of managing simultaneous changes is to employ a form of optimistic concurrency. In this model, no locks against the database rows are taken at all. That means any number of changes to the database could have occurred between the time you first retrieved your objects and the time you submitted your changes. Therefore, unless you want to go with a policy that the last update wins, wiping over whatever else occurred before you, you probably want to be alerted to the fact that the underlying data was changed by someone else. The DataContext has built-in support for optimistic concurrency by automatically detecting change conflicts. Individual updates only succeed if the database's current state matches the state you understood the data to be in when you first retrieved your objects. This happens on a per object basis, only alerting you to violations if they happen to objects you have made changes to. You can control the degree to which the DataContext detects change conflicts when you define your entity classes. Each Column attribute has a property calledUpdateCheck that can be assigned one of three values: Always, Never, and WhenChanged. If not set the default for a Column attribute is Always, meaning the data values represented by that member are always checked for conflicts, that is, unless there is an obvious tie-breaker like a version stamp. A Column attribute has an IsVersion property that allows you to specify whether the data value constitutes a version stamp maintained by the database. If a version exists, then the version is used alone to determine if a conflict has occurred. When a change conflict does occur, an exception will be thrown just as if it were any other error. The transaction surrounding the submission will abort, yet theDataContext will remain the same, allowing you the opportunity to rectify the problem and try again. C# while (retries < maxRetries) { Northwind db = new Northwind("c:\\northwind\\northwnd.mdf"); // fetch objects and make changes here try { db.SubmitChanges(); break; } catch (ChangeConflictException e) { retries++; }

} Visual Basic

Do While retries < maxRetries Dim db As New Northwind("c:\northwind\northwnd.mdf") ' fetch objects and make changes here Try db.SubmitChanges() Exit Do

catch cce As ChangeConflictException retries += 1 End Try

Loop If you are making changes on a middle-tier or server, the easiest thing you can do to rectify a change conflict is to simply start over and try again, recreating the context and reapplying the changes. Additional options are described in the following section. Transactions A transaction is a service provided by databases or any other resource manager that can be used to guarantee that a series of individual actions occur automatically; meaning either they all succeed or they all don't. If they don't, then they are also all automatically undone before anything else is allowed to happen. If no transaction is already in scope, the DataContext will automatically start a database transaction to guard updates when you call SubmitChanges(). You may choose to control the type of transaction used, its isolation level or what it actually encompasses by initiating it yourself. The transaction isolation that theDataContext will use is known as ReadCommitted. C# Product prod = db.Products.Single(p => p.ProductID == 15); if (prod.UnitsInStock > 0) prod.UnitsInStock--; using(TransactionScope ts = new TransactionScope()) { db.SubmitChanges(); ts.Complete(); } Visual Basic Dim product = (From prod In db.Products _ Where prod.ProductID = 15).First If product.UnitsInStock > 0) Then product.UnitsInStock -= 1 End If Using ts As TransactionScope = New TransactionScope()) db.SubmitChanges() ts.Complete() End Using The example above initiates a fully serialized transaction by creating a new transaction scope object. All database commands executed within the scope of the transaction will be guarded by the transaction. C# Product prod = db.Products.Single(p => p.ProductId == 15); if (prod.UnitsInStock > 0) prod.UnitsInStock--; using(TransactionScope ts = new TransactionScope()) { db.ExecuteCommand("exec sp_BeforeSubmit"); db.SubmitChanges(); ts.Complete(); } Visual Basic Dim product = (From prod In db.Products _ Where prod.ProductID = 15).First

If product.UnitsInStock > 0) Then product.UnitsInStock -= 1 End If Using ts As TransactionScope = New TransactionScope()) db.ExecuteCommand(exec sp_BeforeSubmit) db.SubmitChanges() ts.Complete() End Using This modified version of the same example uses the ExecuteCommand() method on the DataContext to execute a stored procedure in the database right before the changes are submitted. Regardless of what the stored procedure does to the database, we can be certain its actions are part of the same transaction. If the transaction completes successfully, the DataContext throws out all the accumulated tracking information and treats the new states of the entities as unchanged. It does not, however, rollback the changes to your objects if the transaction fails. This allows you the maximum flexibility in dealing with problems during change submission. It is also possible to use a local SQL transaction instead of the new TransactionScope. LINQ to SQL offers this capability to help you integrate LINQ to SQL features into pre-existing ADO.NET applications. However, if you go this route you will need to be responsible for much more. C# Product prod = q.Single(p => p.ProductId == 15); if (prod.UnitsInStock > 0) prod.UnitsInStock--; db.Transaction = db.Connection.BeginTransaction(); try { db.SubmitChanges(); db.Transaction.Commit(); } catch { db.Transaction.Rollback(); throw; } finally { db.Transaction = null; } Visual Basic Dim product = (From prod In db.Products _ Where prod.ProductID = 15).First If product.UnitsInStock > 0) Then product.UnitsInStock -= 1 End If db.Transaction = db.Connection.BeginTransaction() Try db.SubmitChanges() db.Transaction.Commit() catch e As Exception db.Transaction.Rollback() Throw e

Finally db.Transaction = Nothing End Try As you can see, using a manually controlled database transaction is a bit more involved. Not only do you have to start it yourself, you have to tell the DataContextexplicitly to use it by assigning it to the Transaction property. Then you must use a try-catch block to encase your submit logic, remembering to explicitly tell the transaction to commit and to explicitly tell the DataContext to accept changes, or to abort the transactions if there is failure at any point. Also, don't forget to set the Transaction property back to null when you are done. Stored Procedures When SubmitChanges() is called, LINQ to SQL generates and executes SQL commands to insert, update, and delete rows in the database. These actions can be overridden by application developers and in their place custom code can be used to perform the desired actions. In this way, alternative facilities like database-stored procedures can be invoked automatically by the change processor. Consider a stored procedure for updating the units in stock for the Products table in the Northwind sample database. The SQL declaration of the procedure is as follows. SQL create proc UpdateProductStock @id int, @originalUnits int, @decrement int as You can use the stored procedure instead of the normal auto-generated update command by defining a method on your strongly typed DataContext. Even if theDataContext class is being auto-generated by the LINQ to SQL code generation tool, you can still specify these methods in a partial class of your own. C# public partial class Northwind : DataContext { ... public void UpdateProduct(Product original, Product current) { // Execute the stored procedure for UnitsInStock update if (original.UnitsInStock != current.UnitsInStock) { int rowCount = this.ExecuteCommand( "exec UpdateProductStock " + "@id={0}, @originalUnits={1}, @decrement={2}", original.ProductID, original.UnitsInStock, (original.UnitsInStock - current.UnitsInStock) ); if (rowCount < 1) throw new Exception("Error updating"); } ... } } Visual Basic Partial Public Class Northwind Inherits DataContext ...

Public Sub UpdateProduct(original As Product, current As Product) Execute the stored procedure for UnitsInStock update If original.UnitsInStock <> current.UnitsInStock Then Dim rowCount As Integer = ExecuteCommand( _ "exec UpdateProductStock " & _ "@id={0}, @originalUnits={1}, @decrement={2}", _ original.ProductID, _ original.UnitsInStock, _ (original.UnitsInStock - current.UnitsInStock) ) If rowCount < 1 Then Throw New Exception(Error updating) End If End If ... End Sub End Class The signature of the method and the generic parameter tells the DataContext to uses this method in place of a generated update statement. The original and current parameters are used by LINQ to SQL for passing in the original and current copies of the object of the specified type. The two parameters are available for optimistic concurrency conflict detection. Note If you override the default update logic, conflict detection is your responsibility. The stored procedure UpdateProductStock is invoked using the ExecuteCommand() method of the DataContext. It returns the number of rows affected and has the following signature: C# public int ExecuteCommand(string command, params object[] parameters); Visual Basic Public Function ExecuteCommand(command As String, _ ParamArray parameters() As Object) As Integer The object array is used for passing parameters required for executing the command. Similar to the update method, insert and delete methods may be specified. Insert and delete methods take only one parameter of the entity type to be updated. For example, methods to insert and delete a Product instance can be specified as follows: C# public void InsertProduct(Product prod) { ... } public void DeleteProudct(Product prod) { ... } Visual Basic Public Sub InsertProduct(prod As Product) ... Public Sub DeleteProudct(prod As Product) ... Entity Classes In-Depth Using Attributes An entity class is just like any normal object class that you might define as part of your application, except that it is annotated with special information that associates it with a particular database table. These annotations are made as custom attributes on your class declaration. The attributes are only meaningful when you use the class in conjunction with LINQ to SQL. They are similar to the XML serialization attributes in the .NET Framework. These "data" attributes provide LINQ to SQL with enough information to translate queries for your objects into SQL queries against the database and changes to your objects into SQL insert, update, and delete commands.

It is also possible to represent the mapping information by using an XML mapping file instead of attributes. This scenario is described in more detail in the External Mapping section. Database Attribute The Database attribute is used to specify the default name of database if it is not supplied by the connection. Database attributes can be applied to strongly typedDataContext declarations. This attribute is optional. Database Attribute

Property Name

Type String

Description Specifies the name of the database. The information is used only if the connection itself does not specify the database name. If this Database attribute does not exist on context declaration and one is not specified by the connection, then database is assumed to have the same name as the context class.

C# [Database(Name="Database#5")] public class Database5 : DataContext { ... } Visual Basic <Database(Name:="Database#5")> _ Public Class Database5 Inherits DataContext ... End Class Table Attribute The Table attribute is used to designate a class as an entity class associated with a database table. Classes with the Table attribute will be treated specially by LINQ to SQL. Table Attribute

Property Name
C#

Type String

Description Specifies the name of the table. If this information is not specified it is assumed that the table has the same name as the entity class.

[Table(Name="Customers")] public class Customer { ... } Visual Basic <Table(Name:="Customers")> _ Public Class Customer ... End Class Column Attribute The Column attribute is used to designate a member of an entity class that represents a column in a database table. It can be applied to any field or property, public, private or internal. Only members identified as columns are persisted when LINQ to SQL saves changes to the database.

Column Attribute

Property Name Storage

Type String String

Description The name of the column in the table or view. If not specified the column is assumed to have the same name as the class member. The name of the underlying storage. If specified it tells LINQ to SQL how to bypass the public property accessor for the data member and interact with the raw value itself. If not specified LINQ to SQL gets and sets the value using the public accessor. The type of database column specified using database types and modifiers. This will be the exact text used to define the column in a T-SQL table declaration command. If not specified the database column type is inferred from the member type. The specific database type is only necessary ifCreateDatabase() method is expected to be used to create an instance of the database. If set to true, the class member represents a column that is part of the table's primary key. If more than one member of the class is designated as the Id, the primary key is said to be a composite of the associated columns. Identifies that the member's column value is auto-generated by the database. Primary keys that are designated IsDbGenerated=true should also have a DBType with the IDENTITY modifier.IsDbGenerated members are synchronized immediately after the data row is inserted and are available after SubmitChanges() completes. Identifies the member's column type as a database timestamp or a version number. Version numbers are incremented and timestamp columns are updated by the database every time the associated row is updated. Members with IsVersion=true are synchronized immediately after the data row is updated. The new values are visible after SubmitChanges() completes. Determines how LINQ to SQL implements optimistic concurrency conflict detection. If no member is designate as IsVersion=true detection is done by comparing original member values with current database state. You can control which members LINQ to SQL uses during conflict detection by giving each member an UpdateCheck enum value. Always: always use this column for conflict detection Never: never use this column for conflict detection WhenChanged: only use this column when the member has been changed by the application Determines if the class member holds the discriminator value for an inheritance hierarchy.

DBType

String

IsPrimaryKey

Bool

IsDbGenerated

Boolean

IsVersion

Boolean

UpdateCheck

UpdateCheck

IsDiscriminator

Boolean

Expression

String

Does not affect LINQ to SQL's operation, but is used during .CreateDatabase() as a raw SQL expression representing the computed column expression. Indicates that the value can contain the null value. This is usually inferred from the CLR type of the entity member. Use this attribute to indicate that a string value is represented as a not nullable column in the database. Specifies if the column is automatically synchronized from the value generated by the database on insert or update commands. Valid values for this tag are OnInsert, Always, and Never.

CanBeNull

Boolean

AutoSync

AutoSync

A typical entity class will use Column attributes on public properties and store actual values in private fields. C# private string _city; [Column(Storage="_city", DBType="NVarChar(15)")] public string City { get { ... } set { ... } } Visual Basic Private _city As String <Column(Storage:="_city", DBType:="NVarChar(15)")> _ public Property City As String Get set End Property The DBType is only specified so that the CreateDatabase() method can construct the table with the most precise type. Otherwise, the knowledge that the underlying column is limited to 15 characters is unused. Members representing the primary key of a database type will often be associated with autogenerated values. C# private string _orderId; [Column(Storage="_orderId", IsPrimaryKey=true, IsDbGenerated = true, DBType="int NOT NULL IDENTITY")] public string OrderId { get { ... } set { ... } } Visual Basic Private _orderId As String <Column(Storage:="_orderId", IsPrimaryKey:=true, _ IsDbGenerated:= true, DBType:="int NOT NULL IDENTITY")> _ public Property OrderId As String Get Set End Property

If you do specify the DBType, make sure to include the IDENTITY modifier. LINQ to SQL will not augment a custom specified DBType. However, if the DBType is left unspecified LINQ to SQL will infer that the IDENTITY modifier is needed when creating the Database via the CreateDatabase() method. Likewise, if the IsVersion property is true, the DBType must specify the correct modifiers to designate a version number or timestamp column. If no DBType is specified, LINQ to SQL will infer the correct modifiers. You can control access to a member associated with an auto-generated column, version stamp, or any column you might want to hide by designating the access level of the member, or even limiting the accessor itself. C# private string _customerId; [Column(Storage="_customerId", DBType="NCHAR(5) ")] public string CustomerID { get { ... } } Visual Basic Private _customerId As String <Column(Storage:="_customerId", DBType:="NCHAR(5)")> _ Public Property CustomerID As String Get End Property The Order's CustomerID property can be made read-only by not defining a set accessor. LINQ to SQL can still get and set the underlying value through the storage member. You can also make a member completely inaccessible to the rest of the application by placing a Column attribute on a private member. This allows the entity class to contain information relevant to the class's business logic without exposing it in general. Even though private members are part of the translated data, since they are private you cannot refer to them in a language-integrated query. By default, all members are used to perform optimistic concurrency conflict detection. You can control whether a particular member is used by specifying itsUpdateCheck value. C# [Column(Storage="_city", UpdateCheck=UpdateCheck.WhenChanged)] public string City { get { ... } set { ... } } Visual Basic <Column(Storage:="_city", UpdateCheck:=UpdateCheck.WhenChanged)> _ Public Property City As String Get Set End Property The following table shows the permissible mappings between database types and the corresponding CLR type. Use this table as a guide when determine which CLR type to use to represent a particular database column. Database Type and Corresponding CLR Type Permissible Mappings

Database Type bit, tinyint, smallint, int,

.NET CLR Type Bye, Int16, Uint16, Int32,

Comments Lossy conversions possible. Values may

bigint bit decimal, numeric, smallmoney, money real, float char, varchar, text, nchar, nvarchar, ntext datetime, smalldatetime uniqueidentifier timestamp

Uint32, Int64, Uint64 Boolean Decimal Single, Double String DateTime Guid Byte[] (Byte() in Visual Basic), Binary

not roundtrip. Scale difference may result in lossy conversion. May not roundtrip. Precision differences. Locale differences possible. Different precision may cause lossy conversion and roundtrip problems. Different collation rules. Sorting may not work as expected. Byte array is treated as a scalar type. User is responsible for allocating adequate storage when constructor is called. It is considered immutable and is not tracked for changes.

binary, varbinary
Association Attribute

Byte[] (Byte() in Visual Basic), Binary

The Association attribute is used to designate a property that represents a database association like a foreign-key to primary-key relationship. Association Attribute

Property Name

Type String

Description The name of the association. This is often the same as the database's foreign-key constraint name. It is used when CreateDatabase() is used to create an instance of the database in order to generate the relevant constraint. It is also used to help distinguish between multiple relationships in a single entity class referring to the same target entity class. In this case, relationship properties on sides of the relationship (if both are defined) must have the same name. The name of the underlying storage member. If specified it tells LINQ to SQL how to bypass the public property accessor for the data member and interact with the raw value itself. If not specified LINQ to SQL gets and sets the value using the public accessor. It is recommended that all association members be properties with separate storage members identified. A comma-separated list of names of one or more members of this entity class that represent the key values on this side of the association. If not specified, the members are assumed to be the members that make up the primary key. A comma-separated list of names of one or more members of

Storage

String

ThisKey

String

OtherKey

String

the target entity class that represent the key values on the other side of the association. If not specified, the members are assumed to be the members that make up the other entity class's primary key. IsUnique Boolean True if there a uniqueness constraint on the foreign key, indicating a true 1:1 relationship. This property is seldom used as 1:1 relationships are nearly impossible to manage within the database. Mostly entity models are defined using 1:n relationships even when they are treated as 1:1 by application developers. True if the target "other" type of the association is the parent of the source type. With foreign-key to primary-key relationships, the side holding the foreign-key is the child and the side holding the primary key is the parent. Used to add delete behavior to this association. For example, "CASCADE" would add "ON DELETE CASCADE" to the FK relationship. If set to null, no delete behavior is added.

IsForeignKey

Boolean

DeleteRule

String

Association properties either represent a single reference to another entity class instance or they represent a collection of references. Singleton references must be encoded in the entity class using the EntityRef<T> (EntityRef (OfT) in Visual Basic) value type to store the actual reference. The EntityRef type is how LINQ to SQL enables deferred loading of references. C# class Order { ... private EntityRef<Customer> _Customer; [Association(Name="FK_Orders_Customers", Storage="_Customer", ThisKey="CustomerID")] public Customer Customer { get { return this._Customer.Entity; } set { this._Customer.Entity = value; // Additional code to manage changes } } } Visual Basic Class Order ... Private _customer As EntityRef(Of Customer) <Association(Name:="FK_Orders_Customers", _ Storage:="_Customer", ThisKey:="CustomerID")> _ public Property Customer() As Customer Get Return _customer.Entity End Get Set (value As Customer) _customer.Entity = value Additional code to manage changes End Set End Class

The public property is typed as Customer, not EntityRef<Customer>. It is important not to expose the EntityRef type as part of the public API, as references to this type in a query will not be translated to SQL. Likewise, an association property representing a collection must use the EntitySet<T> (EntitySet(OfT) in Visual Basic) collection type to store the relationship. C# class Customer { ... private EntitySet<Order> _Orders; [Association(Name="FK_Orders_Customers", Storage="_Orders", OtherKey="CustomerID")] public EntitySet<Order> Orders { get { return this._Orders; } set { this._Orders.Assign(value); } } } Visual Basic Class Customer ... Private _Orders As EntitySet(Of Order) <Association(Name:="FK_Orders_Customers", _ Storage:="_Orders", OtherKey:="CustomerID")> _ public Property Orders() As EntitySet(Of Order) Get Return _Orders End Get Set (value As EntitySet(Of Order)) _Orders.Assign(value) End Property End Class However, since an EntitySet<T> (EntitySet(OfT) in Visual Basic) is a collection, it is valid to use the EntitySet as the return type. It is also valid to disguise the true type of the collection, using the ICollection<T> (ICollection(OfT) in Visual Basic) interface instead. C# class Customer { ... private EntitySet<Order> _Orders; [Association(Name="FK_Orders_Customers", Storage="_Orders", OtherKey="CustomerID")] public ICollection<Order> Orders { get { return this._Orders; } set { this._Orders.Assign(value); } }

} Visual Basic

Class Customer

... Private _orders As EntitySet(Of Order) <Association(Name:="FK_Orders_Customers", _ Storage:="_Orders", OtherKey:="CustomerID")> _ public Property Orders() As ICollection (Of Order) Get Return _orders End Get Set (value As ICollection (Of Order)) _orders.Assign(value) End Property End Class Make certain to use the Assign() method on the EntitySet if you expose a public setter for the property. This allows the entity class to keep using the same collection instance since it may already be tied into the change tracking service. ResultType Attribute This attribute specifies an element type of an enumerable sequence that can be returned from a function that has been declared to return the IMultipleResultsinterface. This attribute can be specified more than once. ResultType Attribute

Propert Type y Type Type

Description Type of the returned results.

StoredProcedure Attribute The StoredProcedure attribute is used to declare that a call to a method defined on the DataContext or Schema type is translated as a call to a database stored procedure. StoredProcedure Attribute

Property Name

Type String

Description The name of the stored procedure in the database. If not specified the stored procedure is assumed to have the same name as the method

Function Attribute The Function attribute is used to declare that a call to a method defined on a DataContext or Schema is translated as a call to a database user-defined scalar or tablevalued function. Function Attribute

Property Name

Type String

Description The name of the function in the database. If not specified the function is assumed to have the same name as the method

Parameter Attribute The Parameter attribute is used to declare a mapping between a method and the parameters of a database stored procedure or user-defined function. Parameter Attribute

Property Name DBType

Type String String

Description The name of the parameter in the database. If not specified the parameter is inferred from the method parameter name. The type of parameter specified using database types and modifiers.

InheritanceMapping Attribute The InheritanceMapping attribute is used to describe the correspondence between a particular discriminator codes and an inheritance subtype. AllInheritanceMapping attributes used for an inheritance hierarchy must be declared on the root type of the hierarchy. InheritanceMapping Attribute

Propety Code Type IsDefault

Type Object Type Boolean

Description The discriminator code value. The Inheritance sub-type. This may be any non-abstract type in the inheritance hierarchy including the root type. Determines if the inheritance sub-type specified is the default type constructed when LINQ to SQL finds a discriminator code that is not defined by the InheritanceMapping attributes. Exactly one of theInheritanceMapping attributes must be declared with IsDefault as true.

Graph Consistency A graph is a general term for a data structure of objects all referring to each other by references. A hierarchy (or tree) is a degenerate form of graph. Domain-specific object models often describe a network of references that are best described as a graph of objects. The health of your object graph is vitally important to the stability of your application. That's why is important to make sure references within the graph remain consistent to your business rules and/or constraints defined in the database. LINQ to SQL does not automatically manage consistency of relationship references for you. When relationships are bidirectional a change to one side of the relationship should automatically update the other. Note that it is uncommon for normal objects to behave this way so it is unlikely that you would have designed your objects this way otherwise. LINQ to SQL does provide a few mechanisms to make this work easy and a pattern for you to follow to make sure you are managing your references correctly. Entity classes generated by the code generation tool will automatically implement the correct patterns. C# public class Customer() { this._Orders = new EntitySet<Order>( new Action<Order>(this.attach_Orders), new Action<Order>(this.detach_Orders)); );} Visual Basic Public Class Customer() _Orders = New EntitySet(Of Order)( _ New Action(Of Order)(attach_Orders), _ New Action(Of Order)(detach_Orders)) End Class

);} The EntitySet<T> (EntitySet(OfT) in Visual Basic) type has a constructor that allows you to supply two delegates to be used as callbacks; the first when an item is added to the collection, the second when it is removed. As you can see from the example, the code you specify for these delegates can and should be written to update the reverse relationship property. This is how the Customer property on an Order instance is automatically changed when an order is added to a customer's Orders collection. Implementing the relationship on the other end is not as easy. The EntityRef<T> (EntityRef(OfT) in Visual Basic) is a value type defined to contain as little additional overhead from the actual object reference as possible. It has no room for a pair of delegates. Instead, the code managing graph consistency of singleton references should be embedded in the property accessors themselves. C# [Association(Name="FK_Orders_Customers", Storage="_Customer", ThisKey="CustomerID")] public Customer Customer { get { return this._Customer.Entity; } set { Customer v = this._Customer.Entity; if (v != value) { if (v != null) { this._Customer.Entity = null; v.Orders.Remove(this); } this._Customer.Entity = value; if (value != null) { value.Orders.Add(this); } } } } Visual Basic <Association(Name:="FK_Orders_Customers", _ Storage:="_Customer", ThisKey:="CustomerID")> _ Public Property Customer As Customer Get Return _Customer.Entity End Get Set (value As Customer) Dim cust As Customer v = _customer.Entity if cust IsNot value Then If cust IsNot Nothing Then _Customer.Entity = Nothing cust.Orders.Remove(Me) End If _customer.Entity = value if value IsNot Nothing Then value.Orders.Add(Me) End If End If End Set End Property

Take a look at the setter. When the Customer property is being changed the order instance is first removed from the current customer's Orders collection and then only later added to the new customer's collection. Notice that before the call to Remove() is made the actual entity reference is set to null. This is done to avoid recursion when the Remove() method is called. Remember, the EntitySet will use callback delegates to assign this object's Customer property to null. The same thing happens right before the call to Add(). The actual entity reference is updated to the new value. This will again curtail any potential recursion and of course accomplish the task of the setter in the first place. The definition of a one-to-one relationship is very similar to the definition of a one-to-many relationship from the side of the singleton reference. Instead of Add()and Remove() being called, a new object is assigned or a null is assigned to sever the relationship. Again, it is vital that relationship properties maintain the consistency of the object graph. If the inmemory object graph is inconsistent with the database data, then a run-time exception is generated when the SubmitChanges method is called. Consider using the code generation tool to maintain consistency work for you. Change Notifications Your objects may participate in the change tracking process. It is not required that they do, but they can considerably reduce the amount of overhead needed to keep track of potential object changes. It is likely that your application will retrieve many more objects from queries than will end up being modified. Without proactive help from your objects, the change tracking service is limited in how it can actually track changes. Since there is no true interception service in the runtime, the formal tracking does not actually occur. Instead, duplicate copies of the objects are stored when they are first retrieved. Later, when you call SubmitChanges(), these copies are used to compare against the ones you've been given. If their values differ, then the object has been modified. This means that every object requires two copies in memory even if you never change them. A better solution is to have the objects themselves announce to the change tracking service when they are indeed changed. This can be accomplished by having the object implement an interface that exposes a callback event. The change tracking service can then wire up each object and receive notifications when they change. C# [Table(Name="Customers")] public partial class Customer: INotifyPropertyChanging { public event PropertyChangingEventHandler PropertyChanging; private void OnPropertyChanging() { if (this.PropertyChanging != null) { this.PropertyChanging(this, emptyEventArgs); } } private string _CustomerID; [Column(Storage="_CustomerID", IsPrimaryKey=true)] public string CustomerID { get { return this._CustomerID; } set { if ((this._CustomerID != value)) { this.OnPropertyChanging("CustomerID"); this._CustomerID = value;

} } } Visual Basic <Table(Name:="Customers")> _ Partial Public Class Customer Inherits INotifyPropertyChanging Public Event PropertyChanging As PropertyChangingEventHandler _ Implements INotifyPropertyChanging.PropertyChanging Private Sub OnPropertyChanging() RaiseEvent PropertyChanging(Me, emptyEventArgs) End Sub private _customerID As String <Column(Storage:="_CustomerID", IsPrimaryKey:=True)> public Property CustomerID() As String Get Return_customerID End Get Set (value As Customer) If _customerID IsNot value Then OnPropertyChanging(CustomerID) _CustomerID = value End IF End Set End Function End Class To assist in improved change tracking, your entity classes must implement the INotifyPropertyChanging interface. It only requires you to define an event calledPropertyChangingthe change tracking service then registers with your event when your objects come into its possession. All you are required to do is raise this event immediately before you are about to change a property's value. Don't forget to put the same event raising logic in your relationship property setters, too. For EntitySets, raise the events in the delegates you supply. C# public Customer() { this._Orders = new EntitySet<Order>( delegate(Order entity) { this.OnPropertyChanging("Orders"); entity.Customer = this; }, delegate(Order entity) { this.onPropertyChanging("Orders"); entity.Customer = null; } ); } Visual Basic Dim _orders As EntitySet(Of Order) Public Sub New() _orders = New EntitySet(Of Order)( _ }

AddressOf OrderAdding, AddressOf OrderRemoving) End Sub Sub OrderAdding(ByVal o As Order) OnPropertyChanging() o.Customer = Me End Sub Sub OrderRemoving(ByVal o As Order) OnPropertyChanging() o.Customer = Nothing End Sub Inheritance LINQ to SQL supports single-table mapping, whereby an entire inheritance hierarchy is stored in a single database table. The table contains the flattened union of all possible data columns for the whole hierarchy and each row has nulls in the columns that are not applicable to the type of the instance represented by the row. The single-table mapping strategy is the simplest representation of inheritance and provides good performance characteristics for many different categories of queries. Mapping To implement this mapping using LINQ to SQL, you need to specify the following attributes and attribute properties on the root class of the inheritance hierarchy:

The [Table] (<Table> in Visual Basic) attribute. An [InheritanceMapping] (<InheritanceMapping> in Visual Basic) attribute for each
class in the hierarchy structure. For non-abstract classes, this attribute must define a Code property (a value that appears in the database table in the Inheritance Discriminator column to indicate which class or subclass this row of data belongs to) and a Type property (which specifies which class or subclass the key value signifies). An IsDefault property on a single [InheritanceMapping] (<InheritanceMapping> in Visual Basic) attribute. This property serves to designate a "fallback" mapping in case the discriminator value from the database table does not match any of the Code values in the inheritance mappings. An IsDiscriminator property for a [Column] (<Column> in Visual Basic) attribute, to signify that this is the column that holds the Code value for inheritance mapping. No special attributes or properties are required on the subclasses. Note especially that subclasses do not have the [Table] (<Table> in Visual Basic) attribute. In the following example, data contained in the Car and Truck subclasses are mapped to the single database table Vehicle. (To simplify the example, the sample code uses fields rather than properties for column mapping.) C# [Table] [InheritanceMapping(Code = "C", Type = typeof(Car))] [InheritanceMapping(Code = "T", Type = typeof(Truck))] [InheritanceMapping(Code = "V", Type = typeof(Vehicle), IsDefault = true)] public class Vehicle { [Column(IsDiscriminator = true)] public string Key; [Column(IsPrimaryKey = true)] public string VIN;

} public class Car : Vehicle { [Column] public int TrimCode; [Column] public string ModelName; } public class Truck : Vehicle { [Column] public int Tonnage; [Column] public int Axles; } Visual Basic <Table> _ <InheritanceMapping(Code:="C", Type:=Typeof(Car))> _ <InheritanceMapping(Code:="T", Type:=Typeof(Truck))> _ <InheritanceMapping(Code:="V", Type:=Typeof(Vehicle), _ IsDefault:=true)> _ Public Class Vehicle <Column(IsDiscriminator:=True)> _ Public Key As String <Column(IsPrimaryKey:=True)> _ Public VIN As String <Column> _ Public MfgPlant As String End Class Public Class Car Inherits Vehicle <Column> _ Public TrimCode As Integer <Column> _ Public ModelName As String End Class Public class Truck Inherits Vehicle <Column> _ public Tonnage As Integer <Column> _ public Axles As Integer End Class The class diagram appears as follows: Figure 1. Vehicle Class Diagram When you view the resulting database diagram in Server Explorer, you see that the columns have all been mapped to a single table, as shown here: Figure 2. Columns Mapped to a Single Table

[Column] public string MfgPlant;

Note that the types of the columns that represent fields in the subtypes have to be nullable or they need to have a default specified. This is necessary for the insert commands to be successful. Querying The following code provides a flavor of how you can use derived types in your queries: C# var q = db.Vehicle.Where(p => p is Truck); //or var q = db.Vehicle.OfType<Truck>(); //or var q = db.Vehicle.Select(p => p as Truck).Where(p => p != null); foreach (Truck p in q) Console.WriteLine(p.Axles); Visual Basic Dim trucks = From veh In db.Vehicle _ Where TypeOf(veh) Is Truck For Each truck In trucks Console.WriteLine(p.Axles) Next Advanced You can expand a hierarchy far beyond the simple sample already provided. Example 1 Here is a much deeper hierarchy and more complex query: C# [Table] [InheritanceMapping(Code = "V", Type = typeof(Vehicle), IsDefault = true)] [InheritanceMapping(Code = "C", Type = typeof(Car))] [InheritanceMapping(Code = "T", Type = typeof(Truck))] [InheritanceMapping(Code = "S", Type = typeof(Semi))] [InheritanceMapping(Code = "D", Type = typeof(DumpTruck))] public class Truck: Vehicle { ... } public class Semi: Truck { ... } public class DumpTruck: Truck { ... } ... // Get all trucks along with a flag indicating industrial application. db.Vehicles.OfType<Truck>.Select(t => new {Truck=t, IsIndustrial=t is Semi || t is DumpTruck } ); Visual Basic <Table> _ <InheritanceMapping(Code:="V", Type:=Typeof(Vehicle), IsDefault:=True)> _ <InheritanceMapping(Code:="C", Type:=Typeof(Car))> _ <InheritanceMapping(Code:="T", Type:=Typeof(Truck))> _ <InheritanceMapping(Code:="S", Type:=Typeof(Semi))> _ <InheritanceMapping(Code:="D", Type:=Typeof(DumpTruck))> _ Public Class Truck

InheritsVehicle Public Class Semi Inherits Truck Public Class DumpTruck InheritsTruck ... ' Get all trucks along with a flag indicating industrial application. Dim trucks = From veh In db.Vehicle _ Where Typeof(veh) Is Truck And _ IsIndustrial = (Typeof(veh) Is Semi _ Or Typeof(veh) Is DumpTruck) Example 2 The following hierarchy includes interfaces: C# [Table] [InheritanceMapping(Code IsDefault = true)] [InheritanceMapping(Code [InheritanceMapping(Code [InheritanceMapping(Code [InheritanceMapping(Code = "V", Type = typeof(Vehicle), = = = = "C", Type = typeof(Car))] "T", Type = typeof(Truck))] "S", Type = typeof(Semi))] "H", Type = typeof(Helicopter))]

public class Truck: Vehicle public class Semi: Truck, IRentableVehicle public class Helicopter: Vehicle, IRentableVehicle Visual Basic <Table> _ <InheritanceMapping(Code:="V", Type:=TypeOf(Vehicle), IsDefault:=True) > _ <InheritanceMapping(Code:="C", Type:=TypeOf(Car)) > _ <InheritanceMapping(Code:="T", Type:=TypeOf(Truck)) > _ <InheritanceMapping(Code:="S", Type:=TypeOf(Semi)) > _ <InheritanceMapping(Code:="H", Type:=TypeOf(Helicopter)) > _ Public Class Truck Inherits Vehicle Public Class Semi InheritsTruck, IRentableVehicle Public Class Helicopter InheritsVehicle, IRentableVehicle Possible queries include the following: C# // Get commercial vehicles ordered by cost to rent. db.Vehicles.OfType<IRentableVehicle>.OrderBy(cv => cv.RentalRate); // Get all non-rentable vehicles db.Vehicles.Where(v => !(v is IRentableVehicle)); Visual Basic ' Get commercial vehicles ordered by cost to rent. Dim rentableVehicles = From veh In _ db.Vehicles.OfType(Of IRentableVehicle).OrderBy( _ Function(cv) cv.RentalRate) ' Get all non-rentable vehicles

Dim unrentableVehicles = From veh In _ db.Vehicles.OfType(Of Vehicle).Where( _ Function(uv) Not (TypeOf(uv) Is IRentableVehicle)) Advanced Topics Creating Databases Since entity classes have attributes describing the structure of the relational database tables and columns, it is possible to use this information to create new instances of your database. You can call the CreateDatabase() method on the DataContext to have LINQ to SQL construct a new database instance with a structure defined by your objects. There are many reasons you might want to do this: you might be building an application that automatically installs itself on a customer system, or a client application that needs a local database to save its offline state. For these scenarios, the CreateDatabase() is idealespecially if a known data provider like SQL Server Express 2005 is available. However, the data attributes may not encode everything about an existing database structure. The contents of user-defined functions, stored procedures, triggers, and check constraints are not represented by the attributes. The CreateDatabase() function will only create a replica of the database using the information it knows, which is the structure of the database and the types of columns in each table. Yet, for a variety of databases this is sufficient. Below is an example of how you can create a new database named MyDVDs.mdf: C# [Table(Name="DVDTable")] public class DVD { [Column(Id = true)] public string Title; [Column] public string Rating; } public class MyDVDs : DataContext { public Table<DVD> DVDs; public MyDVDs(string connection) : base(connection) {} } Visual Basic <Table(Name:="DVDTable")> _ Public Class DVD <Column(Id:=True)> _ public Title As String <Column> _ Public Rating As String End Class Public Class MyDVDs Inherits DataContext Public DVDs As Table(Of DVD) Public Sub New(connection As String) End Class

The object model can be used for creating a database using SQL Server Express 2005 as follows: C# MyDVDs db = new MyDVDs("c:\\mydvds.mdf"); db.CreateDatabase(); Visual Basic Dim db As MyDVDs = new MyDVDs("c:\mydvds.mdf") db.CreateDatabase() LINQ to SQL also provides an API to drop an existing database prior to creating a new one. The database creation code above can be modified to first check for an existing version of the database using DatabaseExists() and then drop it using DeleteDatabase(). C# MyDVDs db = new MyDVDs("c:\\mydvds.mdf"); if (db.DatabaseExists()) { Console.WriteLine("Deleting old database..."); db.DeleteDatabase(); } db.CreateDatabase(); Visual Basic Dim db As MyDVDs = New MyDVDs("c:\mydvds.mdf") If (db.DatabaseExists()) Then Console.WriteLine("Deleting old database...") db.DeleteDatabase() End If db.CreateDatabase() After the call to CreateDatabase(), the new database is able to accept queries and commands like SubmitChanges() to add objects to the MDF file. It is also possible to use CreateDatabase() with a SKU other than SQL Server Express, using either an MDF file or just a catalog name. It all depends on what you use for your connection string. The information in the connection string is used to define the database that will exist, not necessarily one that already exists. LINQ to SQL will fish out the relevant bits of information and use it to determine what database to create and on what server to create it. Of course, you will need database admin rights or equivalent on the server to do so. Interoperating with ADO.NET LINQ to SQL is part of the ADO.NET family of technologies. It is based on services provided by the ADO.NET provider model, so it is possible to mix LINQ to SQL code with existing ADO.NET applications. When you create a LINQ to SQL DataContext, you can supply it with an existing ADO.NET connection. All operations against the DataContextincluding querieswill use the connection you provided. If the connection was already opened LINQ to SQL will honor your authority over the connection and leave it as is when finished with it. Normally LINQ to SQL closes its connection as soon as an operation is finished unless a transaction is in scope. C# SqlConnection con = new SqlConnection( ... ); con.Open(); ... // DataContext takes a connection

Northwind db = new Northwind(con); ... var q = from c in db.Customers where c.City == "London" select c; Visual Basic Dim con As SqlConnection = New SqlConnection( ... ) con.Open() ... ' DataContext takes a connection Dim db As Northwind = new Northwind(con) ... Dim q = From c In db.Customers _ Where c.City = "London" _ Select c You can always access the connection used by your DataContext through the Connection property and close it yourself. C# db.Connection.Close(); Visual Basic db.Connection.Close() You can also supply the DataContext with your own database transaction, in case your application has already initiated one and you desire the DataContext to play along with it. C# IDbTransaction = con.BeginTransaction(); ... db.Transaction = myTransaction; db.SubmitChanges(); db.Transaction = null; Visual Basic Dim db As IDbTransaction = con.BeginTransaction() ... db.Transaction = myTransaction db.SubmitChanges() db.Transaction = Nothing Whenever a Transaction is set, the DataContext will use it whenever it issues a query or executes a command. Don't forget to assign the property back to nullwhen you are done. However, the preferred method of doing transactions with the .NET Framework is to use the TransactionScope object. It allows you to make distributed transactions that work across databases and other memory resident resource managers. The idea is that transaction scopes start cheap, only promoting themselves to full on distributed transaction when they actually do refer to multiple databases or multiple connections within the scope of the transaction. C# using(TransactionScope ts = new TransactionScope()) { db.SubmitChanges(); ts.Complete(); }

Visual Basic Using ts As TransactionScope= New TransactionScope() db.SubmitChanges() ts.Complete() End Using Executing SQL statements directly Connections and transactions are not the only way you can interoperate with ADO.NET. You might find that in some cases the query or submit changes facility of theDataContext is insufficient for the specialized task you may want to perform. In these circumstances it is possible to use the DataContext to issue raw SQL commands directly to the database. The ExecuteQuery() method lets you execute a raw SQL query and converts the result of your query directly into objects. For example, assuming that the data for the Customer class is spread over two tables customer1 and customer2, the following query returns a sequence of Customer objects. C# IEnumerable<Customer> results = db.ExecuteQuery<Customer>( @"select c1.custid as CustomerID, c2.custName as ContactName from customer1 as c1, customer2 as c2 where c1.custid = c2.custid" ); Visual Basic Dim results As IEnumerable(Of Customer) = _ db.ExecuteQuery(Of Customer)( _ "select c1.custid as CustomerID, " & _ "c2.custName as ContactName " & _ "from customer1 as c1, customer2 as c2 "& _ "where c1.custid = c2.custid" ) As long as the column names in the tabular results match column properties of your entity class LINQ to SQL will materialize your objects out of any SQL query. The ExecuteQuery() method also allows parameters. In the following code, a parameterized query is executed: C# IEnumerable<Customer> results = db.ExecuteQuery<Customer>( "select contactname from customers where city = {0}", "London" ); Visual Basic Dim results As IEnumerable(Of Customer) = _ db.ExecuteQuery(Of Customer)( _ "select contactname from customers where city = {0}", _ "London" ) The parameters are expressed in the query text using the same curly notation used by Console.WriteLine() and String.Format(). In fact, String.Format() is actually called on the query string you provide, substituting the curly braced parameters with generated parameter names like @p0, @p1 ..., @p(n).

Change Conflict Resolution Description A change conflict occurs when the client attempts to submit changes to an object and one or more values used in the update check have been updated in the database since the client last read them. Note Only members mapped as UpdateCheck.Always or UpdateCheck.WhenChanged participate in optimistic concurrency checks. No check is performed for members marked UpdateCheck.Never. Resolution of this conflict includes discovering which members of the object are in conflict, and then deciding what to do about it. Note that optimistic concurrency might not be the best strategy in your particular situation. Sometimes it is perfectly reasonable to "let the last update win". Detecting, Reporting, and Resolving Conflicts in LINQ to SQL Conflict resolution is the process of refreshing a conflicting item by querying the database again and reconciling any differences. When an object is refreshed, the change tracker has the old original values and the new database values. LINQ to SQL then determines whether the object is in conflict or not. If it is, LINQ to SQL determines which members are involved. If the new database value for a member is different from the old original (which was used for the update check that failed), this is a conflict. Any member conflicts are added to a conflict list. For example, in the following scenario, User1 begins to prepare an update by querying the database for a row. Before User1 can submit the changes, User2 has changed the database. User1's submission fails because the values expected for Col B and Col C have changed. Database Update Conflict

User Col A Original state Alfreds User 1 User 2 Alfred

Col B Maria Mary

Col C Sales Marketing Service

In LINQ to SQL, objects that fail to update because of optimistic concurrency conflicts cause an exception (ChangeConflictException) to be thrown. You can specify whether the exception should be thrown at the first failure or whether all updates should be attempted with any failures being accumulated and reported in the exception. // [C#] db.SubmitChanges(ConflictMode.FailOnFirstConflict); db.SubmitChanges(ConflictMode.ContinueOnConflict); ' [Visual Basic] db.SubmitChanges(ConflictMode.FailOnFirstConflict) db.SubmitChanges(ConflictMode.ContinueOnConflict) When thrown, the exception provides access to an ObjectChangeConflict collection. Details are available for each conflict (mapped to a single failed update attempt), including access to the MemberConflicts list. Each member conflict maps to a single member in the update that failed the concurrency check. Conflict Handling In the preceding scenario, User1 has the RefreshMode options described below for reconciling the differences before attempting to resubmit. In all cases, the record on the client is first "refreshed" by pulling down the updated data from the database. This action ensures that the next update attempt will not fail on the same concurrency checks.

Here, User1 chooses to merge database values with the current client values so that the database values are overwritten only when the current changeset has also modified that value. (See Example 1 later in this section.) In the scenario above, after conflict resolution, the result in the database is as follows: KeepChanges

KeepChanges

Col A Alfred (User 1)

Col B Mary (User 2)

Col C Marketing (User 1)

Col A: User1's change (Alfred) appears. Col B: User2's change (Mary) appears. This value was merged because User1 has not changed it. Col C: User1's change (Marketing) appears. User2's change (Service) is not merged because User1 has also changed that item. Below, User1 chooses to overwrite any database values with the current values. (See Example 2 later in this section.) After the refresh, User1's changes are submitted. The result in the database is as follows: KeepCurrentValues

Col A KeepCurrentValues Alfred (User 1)

Col B Maria (Original)

Col C Marketing (User 1)

Col A: User1's change (Alfred) appears. Col B: The original Maria remains; User2's change is discarded. Col C: User1's change (Marketing) appears. User2's change (Service) is discarded. In the next scenario, User1 chooses to allow the database values to overwrite the current values in the client. (See Example 3 later in this section.) In the scenario above, after conflict resolution, the result in the database is as follows: OverwriteCurrentValues

Col A Col B OverwriteCurrentValues Alfreds (Original) Mary (User 2)

Col C Service (User 2)

Col A: The original value (Alfreds) remains; User1's value (Alfred) is discarded. Col B: User2's change (Mary) appears. Col C: User2's change (Service) appears. User1's change (Marketing) is discarded. After conflicts have been resolved, you can attempt a resubmit. Because this second update might also fail, consider using a loop for update attempts. Examples The following code excerpts show various informational members and techniques at your disposal for discovering and resolving member conflicts. Example 1 In this example, conflicts are resolved "automatically." That is, database values are merged with the current client values unless the client has also changed that value (KeepChanges). No inspection or custom handling of individual member conflicts takes place. C# try { context.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException e) {

//automerge database values into current for members //that client has not modified context.ChangeConflicts.Resolve(RefreshMode.KeepChanges); } //submit succeeds on second try context.SubmitChanges(ConflictMode.FailOnFirstConflict); Visual Basic Try context.SubmitChanges(ConflictMode.ContinueOnConflict) Catch e As ChangeConflictException ' automerge database values into current for members ' that client has not modified context.ChangeConflicts.Resolve(RefreshMode.KeepChanges) End Try ' submit succeeds on second try context.SubmitChanges(ConflictMode.FailOnFirstConflict) Example 2 In this example, conflicts are resolved again without any custom handling. But this time, database values are not merged into current client values. C# try { context.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException e) { foreach (ObjectChangeConflict cc in context.ChangeConflicts) { //No database values are automerged into current cc.Resolve(RefreshMode.KeepCurrentValues); } } Visual Basic Try context.SubmitChanges(ConflictMode.ContinueOnConflict) Catch e As ChangeConflictException For Each cc As ObjectChangeConflict In context.ChangeConflicts No database values are automerged into current cc.Resolve(RefreshMode.KeepCurrentValues) Next End Try Example 3 Here again, no custom handling takes place. But in this case, all client values are updated with the current database values. C# try { context.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException e) { foreach (ObjectChangeConflict cc in context.ChangeConflicts) { //No database values are automerged into current cc.Resolve(RefreshMode.OverwriteCurrentValues); } } Visual Basic Try context.SubmitChanges(ConflictMode.ContinueOnConflict)

Catch e As ChangeConflictException For Each cc As ObjectChangeConflict In context.ChangeConflicts ' No database values are automerged into current cc.Resolve(RefreshMode. OverwriteCurrentValues) Next End Try Example 4 This example shows a way of accessing information on an entity in conflict. C# try { user1.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException e) { Console.WriteLine("Optimistic concurrency error"); Console.ReadLine(); foreach (ObjectChangeConflict cc in user1.ChangeConflicts) { ITable table = cc.Table; Customers entityInConflict = (Customers)cc.Object; Console.WriteLine("Table name: {0}", table.Name); Console.Write("Customer ID: "); Console.WriteLine(entityInConflict.CustomerID); } } Visual Basic Try context.SubmitChanges(ConflictMode.ContinueOnConflict) Catch e As ChangeConflictException Console.WriteLine("Optimistic concurrency error") Console.ReadLine() For Each cc As ObjectChangeConflict In context.ChangeConflicts Dim table As ITable = cc.Table Dim entityInConflict As Customers = CType(cc.Object, Customers) Console.WriteLine("Table name: {0}", table.Name) Console.Write("Customer ID: ") Console.WriteLine(entityInConflict.CustomerID) Next End Try Example 5 This example adds a loop through the individual members. Here you could provide custom handling of any member. Note Add using System.Reflection; to provide MemberInfo. C# try { user1.SubmitChanges(ConflictMode.ContinueOnConflict); } catch (ChangeConflictException e) { Console.WriteLine("Optimistic concurrency error"); Console.ReadLine(); foreach (ObjectChangeConflict cc in user1.ChangeConflicts) { ITable table = cc.Table; Customers entityInConflict = (Customers)cc.Object; Console.WriteLine("Table name: {0}", table.Name); Console.Write("Customer ID: ");

} } Visual Basic Try

Console.WriteLine(entityInConflict.CustomerID); foreach (MemberChangeConflict mc in cc.MemberConflicts) { object currVal = mc.CurrentValue; object origVal = mc.OriginalValue; object databaseVal = mc.DatabaseValue; MemberInfo mi = mc. Member; Console.WriteLine("Member: {0}", mi.Name); Console.WriteLine("current value: {0}", currVal); Console.WriteLine("original value: {0}", origVal); Console.WriteLine("database value: {0}", databaseVal); Console.ReadLine(); }

user1.SubmitChanges(ConflictMode.ContinueOnConflict) Catch e As ChangeConflictException Console.WriteLine("Optimistic concurrency error") Console.ReadLine() For Each cc As ObjectChangeConflict In context.ChangeConflicts Dim table As ITable = cc.Table Dim entityInConflict As Customers = CType(cc.Object, Customers) Console.WriteLine("Table name: {0}", table.Name) Console.Write("Customer ID: ") Console.WriteLine(entityInConflict.CustomerID) For Each mc As MemberChangeConflict In cc.MemberConflicts Dim currVal As Object = mc.CurrentValue Dim origVal As Object = mc.OriginalValue Dim databaseVal As Object = mc.DatabaseValue Dim mi As MemberInfo = mc.Member Console.WriteLine("Member: {0}", mi.Name) Console.WriteLine("current value: {0}", currVal) Console.WriteLine("original value: {0}", origVal) Console.WriteLine("database value: {0}", databaseVal) Console.ReadLine() Next Next End Try Stored Procedures Invocation LINQ to SQL supports stored procedures and user-defined functions. LINQ to SQL maps these database-defined abstractions to code-generated client objects, so that you can access them in a strongly typed manner from client code. You can easily discover these methods using IntelliSense, and the method signatures resemble as closely as possible the signatures of the procedures and functions defined in the database. A result set returned by a call to a mapped procedure is a strongly typed collection. LINQ to SQL can automatically generate the mapped methods, but also supports manual mapping in situations where you choose not to use code generation. LINQ to SQL maps stored procedures and functions to methods through the use of attributes. The StoredProcedure, Parameter, and Function attributes all support a Name property, and the Parameter attribute also supports a DBType property. Here are two examples: C# [StoredProcedure()] public IEnumerable<CustOrderHistResult> CustOrderHist(

[Parameter(Name="CustomerID", DBType="NChar(5)")] string customerID) { IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), customerID); } return ((IEnumerable<CustOrderHistResult>)(result.ReturnValue));

[Function(Name="[dbo].[ConvertTemp]")] public string ConvertTemp(string string) { ... } Visual Basic <StoredProcedure()> _ Public Function CustOrderHist( _ <Parameter(Name:="CustomerID", DBType:="NChar(5)")> _ customerID As String) As IEnumerable(Of CustOrderHistResult) Dim result As IExecuteResult = ExecuteMethodCall(Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo), customerID) Return CType(result.ReturnValue, IEnumerable(Of CustOrderHistResult)) End Function <Function(Name:="[dbo].[ConvertTemp]")> _ Public Function ConvertTemp(str As String) As String The following examples show mappings for various kinds of stored procedures. Example 1 The following stored procedure takes a single input parameter and returns an integer: CREATE PROCEDURE GetCustomerOrderCount(@CustomerID nchar(5)) AS Declare @count int SELECT @count = COUNT(*) FROM ORDERS WHERE CustomerID = @CustomerID RETURN @count The mapped method would be as follows: C# [StoredProcedure(Name = "GetCustomerOrderCount")] public int GetCustomerOrderCount( [Parameter(Name = "CustomerID")] string customerID) { IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), customerID); return (int) result.ReturnValue; } Visual Basic <StoredProcedure (Name:="GetCustomerOrderCount")> _ public Function GetCustomerOrderCount( _ <Parameter(Name:= "CustomerID")> customerID As String) As Integer Dim result As IExecuteResult = ExecuteMethodCall(Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo), customerID) return CInt(result.ReturnValue) End Function Example 2 When a stored procedure can return multiple result shapes, the return type cannot be strongly typed to a single projection shape. In the following example, the result shape depends on the input:

CREATE PROCEDURE VariableResultShapes(@shape int) AS if(@shape = 1) select CustomerID, ContactTitle, CompanyName from customers else if(@shape = 2) select OrderID, ShipName from orders The mapped method is as follows: C# [StoredProcedure(Name = "VariableResultShapes")] [ResultType(typeof(Customer))] [ResultType(typeof(Order))] public IMultipleResults VariableResultShapes(System.Nullable<int> shape) { IExecuteResult result = this.ExecuteMethodCallWithMultipleResults(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), shape); return (IMultipleResults) result.ReturnValue; } Visual Basic <StoredProcedure(Name:= "VariableResultShapes")> _ <ResultType(typeof(Customer))> _ <ResultType(typeof(Order))> _ public VariableResultShapes(shape As Integer?) As IMultipleResults Dim result As IExecuteResult = ExecuteMethodCallWithMultipleResults(Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo), shape) return CType(result.ReturnValue, IMultipleResults) End Function You could use this stored procedure as follows: C# IMultipleResults result = db.VariableResultShapes(1); foreach (Customer c in result.GetResult<Customer>()) { Console.WriteLine(c.CompanyName); } result = db.VariableResultShapes(2); foreach (Order o in result.GetResult<Order>()) { Console.WriteLine(o.OrderID); } Visual Basic Dim result As IMultipleResults = db.VariableResultShapes(1) For Each c As Customer In result.GetResult(Of Customer)() Console.WriteLine(c.CompanyName) Next result = db.VariableResultShapes(2); For Each o As Order In result.GetResult(Of Order)() Console.WriteLine(o.OrderID) Next } Here you need to use the GetResult pattern to get an enumerator of the correct type, based on your knowledge of the stored procedure. LINQ to SQL can generate all possible projection types, but has no way of knowing in what order they will be returned. The only way you can know which generated projection types correspond to a mapped method is by using generated code comments on the methods.

Example 3 Here is the T-SQL of a stored procedure that returns multiple result shapes sequentially: CREATE PROCEDURE MultipleResultTypesSequentially AS select * from products select * from customers LINQ to SQL would map this procedure just as in Example 2 above. In this case, however, there are two sequential resultsets. C# [StoredProcedure(Name="MultipleResultTypesSequentially")] [ResultType(typeof(Product))] [ResultType(typeof(Customer))] public IMultipleResults MultipleResultTypesSequentially() { return ((IMultipleResults)( this.ExecuteMethodCallWithMultipleResults (this, ((MethodInfo)(MethodInfo.GetCurrentMethod()))).ReturnValue ) ); } Visual Basic <StoredProcedure(Name:="MultipleResultTypesSequentially")> _ <ResultType(typeof(Customer))> _ <ResultType(typeof(Order))> _ public Function MultipleResultTypesSequentially() As IMultipleResults Return CType( ExecuteMethodCallWithMultipleResults (Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo)), _ IMultipleResults).ReturnValue End Function You could use this stored procedure as follows: C# IMultipleResults sprocResults = db.MultipleResultTypesSequentially(); //first read products foreach (Product p in sprocResults.GetResult<Product>()) { Console.WriteLine(p.ProductID); } //next read customers foreach (Customer c in sprocResults.GetResult<Customer>()){ Console.WriteLine(c.CustomerID); } Visual Basic Dim sprocResults As IMultipleResults = db.MultipleResultTypesSequentially() ' first read products For Each P As Product In sprocResults.GetResult(Of Product)() Console.WriteLine(p.ProductID) Next ' next read customers For Each c As Customer c In sprocResults.GetResult(Of Customer)() Console.WriteLine(c.CustomerID) Next

Example 4 LINQ to SQL maps out parameters to reference parameters (ref keyword), and for value types declares the parameter as nullable (for example, int?). The procedure in the following example takes a single input parameter and returns an out parameter. CREATE PROCEDURE GetCustomerCompanyName( @customerID nchar(5), @companyName nvarchar(40) output ) AS SELECT @companyName = CompanyName FROM Customers WHERE CustomerID=@CustomerID The mapped method is as follows: C# [StoredProcedure(Name = "GetCustomerCompanyName")] public int GetCustomerCompanyName( string customerID, ref string companyName) { IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), customerID, companyName); companyName = (string)result.GetParameterValue(1); return (int)result.ReturnValue;

} Visual Basic

<StoredProcedure(Name:="GetCustomerCompanyName")> _ Public Function GetCustomerCompanyName( _ customerID As String, ByRef companyName As String) As Integer Dim result As IExecuteResult = ExecuteMethodCall(Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo), customerID, _ companyName) companyName = CStr(result.GetParameterValue(1)) return CInt(result.ReturnValue) End Function In this case, the method does not have an explicit return value, but the default return value is mapped anyway. For the output parameter, a corresponding output parameter is used as expected. You would call the above stored procedure as follows: C# string CompanyName = ""; string customerID = "ALFKI"; db.GetCustomerCompanyName(customerID, ref CompanyName); Console.WriteLine(CompanyName); Visual Basic Dim CompanyName As String = "" Dim customerID As String = "ALFKI" db.GetCustomerCompanyName(customerID, CompanyName) Console.WriteLine(CompanyName)

User-defined Functions LINQ to SQL supports both scalar-valued and table-valued functions, and supports the in-line counterpart of both. LINQ to SQL handles inline scalar calls similarly to the way system-defined functions are called. Consider the following query: C# var q = from p in db.Products select new { pid = p.ProductID, unitp = Math.Floor(p.UnitPrice.Value) }; Visual Basic Dim productInfos = From prod In db.Products _ Select p.ProductID, price = Math.Floor(p.UnitPrice.Value) Here the method call Math.Floor is translated to a call to the system function 'FLOOR'. In the same way, a call to a function that is mapped to a UDF is translated to a call to the UDF in SQL. Example 1 Here is a scalar user-defined function (UDF) ReverseCustName(). In SQL Server, the function might be defined as follows: CREATE FUNCTION ReverseCustName(@string varchar(100)) RETURNS varchar(100) AS BEGIN DECLARE @custName varchar(100) -- Impl. left as exercise for the reader RETURN @custName END You can map a client method defined on a schema class to this UDF using the code below. Note that the body of the method constructs an expression that captures the intent of the method call, and passes that expression to the DataContext for translation and execution. (This direct execution happens only if the function is called.) C# [Function(Name = "[dbo].[ReverseCustName]")] public string ReverseCustName(string string1) { IExecuteResult result = this.ExecuteMethodCall(this, (MethodInfo)(MethodInfo.GetCurrentMethod())), string1); return (string) result.ReturnValue; } Visual Basic Function(Name:= "[dbo].[ReverseCustName]")> _ Public Function ReverseCustName(string1 As String) As String Dim result As IExecuteResult = ExecuteMethodCall(Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo), string1) return CStr(result.ReturnValue) Example 2 In the following query, you can see an inline call to the generated UDF method ReverseCustName. In this case the function is not executed immediately. The SQL built for this query translates to a call to the UDF defined in the database (see the SQL code following the query).

C# var q = from c in db.Customers select new { c.ContactName, Title = db.ReverseCustName(c.ContactTitle) }; Visual Basic Dim customerInfos = From cust In db.Customers _ Select c.ContactName, _ Title = db.ReverseCustName(c.ContactTitle)

SELECT [t0].[ContactName], dbo.ReverseCustName([t0].[ContactTitle]) AS [Title] FROM [Customers] AS [t0] When you call the same function outside a query, LINQ to SQL creates a simple query from the method call expression with the following SQL syntax (where the parameter @p0 is bound to the constant passed in): In LINQ to SQL: C# string str = db.ReverseCustName("LINQ to SQL"); Visual Basic Dim str As String = db.ReverseCustName("LINQ to SQL") Converts to: SELECT dbo.ReverseCustName(@p0) Example 3 A table-valued function (TVF) returns a single result set (unlike stored procedures, which can return multiple result shapes). Because the TVF return type is table, you can use a TVF anywhere in SQL that you can use a table, and you can treat the TVF in the same way as you would a table. Consider the following SQL Server definition of a table-valued function: CREATE FUNCTION ProductsCostingMoreThan(@cost money) RETURNS TABLE AS RETURN SELECT ProductID, UnitPrice FROM Products WHERE UnitPrice > @cost This function explicitly states that it returns a TABLE, so the returned result set structure is implicitly defined. LINQ to SQL maps the function as follows: C# [Function(Name = "[dbo].[ProductsCostingMoreThan]")] public IQueryable<Product> ProductsCostingMoreThan( System.Nullable<decimal> cost) { return this.CreateMethodCallQuery<Product>(this, (MethodInfo)MethodInfo.GetCurrentMethod(), cost);

} Visual Basic

<Function(Name:="[dbo].[ProductsCostingMoreThan]")> _ Public Function ProductsCostingMoreThan( cost As System.Nullable(Of Decimal)) As IQueryable(Of Product) Return CreateMethodCallQuery(Of Product)(Me, _ CType(MethodInfo.GetCurrentMethod(), MethodInfo), cost) The following SQL code shows that you can join to the table returned by the function and otherwise treat it as you would any other table: SELECT p2.ProductName, p1.UnitPrice FROM dbo.ProductsCostingMoreThan(80.50) AS p1 INNER JOIN Products AS p2 ON p1.ProductID = p2.ProductID In LINQ to SQL, the query would be rendered as follows (using the new 'join' syntax): C# var q = from p in db.ProductsCostingMoreThan(80.50m) join s in db.Products on p.ProductID equals s.ProductID select new {p.ProductID, s.UnitPrice}; Visual Basic Dim productInfos = From costlyProd In db.ProductsCostingMoreThan(80.50m) _ Join prod In db.Products _ On costlyProd.ProductID Equals prod.ProductID _ Select costlyProd.ProductID, prod.UnitPrice LINQ to SQL Limitations on Stored Procedures LINQ to SQL supports code generation for stored procedures that return statically determined result sets. Thus the LINQ to SQL code generator does not support the following: Stored procedures that use dynamic SQL to return result sets. When a stored procedure contains conditional logic to build a dynamic SQL statement, LINQ to SQL cannot acquire metadata for the resultset because the query used to generate the resultset is unknown until run time. Stored procedures that produce results based on temporary table. The Entity Class Generator Tool If you have an existing database, it is unnecessary to create a complete object model by hand just to represent it. The LINQ to SQL distribution comes with a tool called SQLMetal. It is a commandline utility that automates the task of creating entity classes by inferring the appropriate classes from the database metadata. You can use SQLMetal to extract SQL metadata from a database and generate a source file containing entity class declarations. Alternatively, you can split the process into two steps, first generating an XML file representing the SQL metadata and then later translating that XML file into a source file containing class declarations. This split process allows you to retain the metadata as a file so you may edit it. The extraction process producing the file make a few inferences along the way about appropriate class and property names given the table and column names of the database. You might find it necessary to edit the XML file in order for the generator to produce more pleasing results or to hide aspects of the database that you don't want present in your objects. The simplest scenario to use SQLMetal is to directly generate classes from an existing database. Here is how to invoke the tool: C# SqlMetal /server:.\SQLExpress /database:Northwind /pluralize /namespace:nwind /code:Northwind.cs

Visual Basic SqlMetal /server:.\SQLExpress /database:Northwind /pluralize /namespace:nwind /code:Northwind.vb /language:vb Executing the tool creates a Northwind .cs or .vb file that contains the object model generated by reading the database metadata. This usage works well if the names of the tables in the database are similar to the names of the objects that you want to generate. If not you'll want to take the two-step approach. To instruct SQLMetal to generate a DBML file use the tool as follows: SqlMetal /server:.\SQLExpress /database:Northwind /pluralize /xml:Northwind.dbml Once the dbml file is generated, you can go ahead and annotate it with class and property attribute to describe how tables and columns map to classes and properties. Once you have finished annotating the dbml file, you can generate your object model by running the following command: C# SqlMetal /namespace:nwind /code:Northwind.cs Northwind.dbml Visual Basic SqlMetal /namespace:nwind /code:Northwind.vb Northwind.dbml /language:vb The SQLMetal usage signature is as follows: SqlMetal [options] [filename] The following is a table showing the available command line options for SQLMetal. Command Line Options for SQLMetal

Option /server:<name> /database:<name> /user:<name> /password:<name> /views /functions /sprocs /code[:<filename>] /language:<language> /xml[:<filename>]

Description Indicates the server to connect to in order to access the database. Indicates the name of the database to read metadata from. Login user id for the server. Login password for the server. Extract database views. Extract database functions. Extract stored procedures. Indicates that the output of the tool is a source file of entity class declarations. Use Visual Basic or C# (default). Indicates that the output of the tools is an DBML file describing the database metadata and the first guess approximation of class and property names. Indicates that an external mapping file should be used instead of attributes. Indicates that the tool should perform English language pluralizing / de-pluralizing heuristic to the names of the tables in order to produce appropriate class and property names. Indicates the namespace the entity classes will be generated in. Timeout value in seconds to use for database commands.

/map[:<filename>] /pluralize

/namespace:<name> /timeout:<seconds>

Note In order to extract the metadata from an MDF file, you must specify the MDF file name after all other options. If no /server is specifiedlocalhost is assumed.

Generator Tool DBML Reference The DBML (Database Mapping Language) file is foremost a description of the SQL metadata for a given database. It is extracted by SQLMetal by looking at the database metadata. The same file is also used by SQLMetal to generate a default object model to represent the database. Here is a prototypical example of the DBML syntax: <?xml version="1.0" encoding="utf-16"?> <Database Name="Northwind" EntityNamespace="Mappings.FunctionMapping" ContextNamespace="Mappings.FunctionMapping" Provider="System.Data.Linq.SqlClient.Sql2005Provider" xmlns="http://schemas.microsoft.com/dsltools/LINQ to SQLML"> <Table Name="Categories"> <Type Name="Category"> <Column Name="CategoryID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsReadOnly="False" IsPrimaryKey="True" IsDbGenerated="True" CanBeNull="False" /> <Column Name="CategoryName" Type="System.String" DbType="NVarChar(15) NOT NULL" CanBeNull="False" /> <Column Name="Description" Type="System.String" DbType="NText" CanBeNull="True" UpdateCheck="Never" /> <Column Name="Picture" Type="System.Byte[]" DbType="Image" CanBeNull="True" UpdateCheck="Never" /> <Association Name="FK_Products_Categories" Member="Products" ThisKey="CategoryID" OtherKey="CategoryID" OtherTable="Products" DeleteRule="NO ACTION" /> </Type> </Table> <Function Name="GetCustomerOrders"> <Parameter Name="customerID" Type="System.String" DbType="NChar(5)" /> <ElementType Name="GetCustomerOrdersResult"> <Column Name="OrderID" Type="System.Int32" DbType="Int" CanBeNull="True" /> <Column Name="ShipName" Type="System.String" DbType="NVarChar(40)" CanBeNull="True" /> <Column Name="OrderDate" Type="System.DateTime" DbType="DateTime" CanBeNull="True" /> <Column Name="Freight" Type="System.Decimal" DbType="Money" CanBeNull="True" /> </ElementType> </Function> </Database> The elements and their attributes are described as follows. Database This is the outermost element in the XML format. This element maps loosely to the Database attribute on the generated DataContext. Database Attributes

Attribute Name

Type String

Default None

Description The name of the database. present, and if generating

a DataContext, will attach Database attribute to it with name. Also used as name of DataContext class if the attribute is not present. EntityNamespace Strong None

Default namespace for clas generated from Type eleme within Table elements. If n namespace is specified her entity classes are generated root namespace.

ContextNamespace String

None

Default namespace for the generatedDataContext cla no namespace is specified that the DataContext class generated in the root names

Class

String

Database.Name

The name of the generated DataContext cla no present, use the Name attribute of the Database element.

AccessModifier

AccessModifier

Public

The accessibility level of th generatedDataContext cla Valid values are Public,Protected, Inte nd Private. The base type of the DataContext class.

BaseType Provider

String String

System.Data.Linq.DataContext

System.Data.Linq.SqlClient.Sql2005Provider The provider of the DataContext, use Sql2 provider as default False

ExternalMapping Serialization

Boolean

Specify if the DBML is use generating external mappin

SerializationMode SerializationMode.None

Specify if the generated DataContext an classes are serializable.

Database Sub-Element Attributes

Sub-Element <Table>

Element Type Occurrence Range Table 0-unbounded

Description Represents a SQL Server table or view that will be mapped either to a single type or to an inheritance hierarchy. Represents a SQL Server stored procedure or a db function that will be mapped to a method in the

<Function>

Function

0-unbounded

generated DataContext class. <Connection>


Table This element represents a database table (or a view) that will be mapped either to a single type or to an inheritance hierarchy. This element maps loosely to the Table attribute on the generated entity class. Table Attributes

Connection

0-1

Represents the database connection thisDataContext will use.

Attribute Name

Type String

Default (required)

Description The name of the table within the database. Serves as the base of the default name for the table adapter, if needed. The name of the member field generated for this table within theDataContext class. The accessibility level of the Table<T> reference within the DataContext. Valid values are Public, Protected, Internal and Private.

Member AccessModifier

String AccessModifier

Table.Name Public

Table Sub-Element Attributes

Sub-Element <Type> <InsertFunction>

Element Type Type TableFunction

Occurrence Range 1-1 0-1

Description Represents the type or inheritance hierarchy mapped to this table. The method for inserting. When it is present, a method InsertTis generated. The method for updating. When it is present, a methodUpdateT is generated. The method for deleting. When it is present, a method DeleteTis generated.

<UpdateFunction>

TableFunction

0-1

<DeleteFunction>

TableFunction

0-1

Type This element represents a type definition for either a Table or a stored procedure result shape. This will code-gen into a new CLR type with the columns and associations specified. Type may also represent a component of an inheritance hierarchy, with multiple types mapping to the same table. In this case the Type elements are nested to represent the parent-child inheritance relationships and are differentiated in the database by the InheritanceCode specified. Type Attributes

Attribute Name InheritanceCode

Type String String

Default Description (required) The name of the CLR type to be generated. None If this type is participating in inheritance, it can

have an associated inheritance code to distinguish between CLR types when loading rows from the table. The Type whose InheritanceCode matches the value of the IsDiscriminator column is used to instantiate the loaded object. If the inheritance code is not present, the generated entity class is abstract. IsInheritanceDefault Boolean False If this is true for a Type in an inheritance hierarchy, this type will be used when loading rows that do not match on any defined inheritance codes. The accessibility level of the CLR type being created. Valid values are: Public, Protected, Internal and Private. A type can have a unique Id. Id of a type can be used by other tables or functions. Id only appears in DBML file, not in the object model. IdRef is used to refer to another type's Id. If IdRef is present in a type element, the type element must only contain the IdRefinformation. IdRef only appears in DBML file, not in the object model. Description Represents a property within this type that will be bound to a field in this type's table. Represents a property within this type that will be bound to one end of a foreign key relationship between tables. Represents subtypes of this type within an inheritance hierarchy.

AccessModifier

AccessModifier

Public

Id

String

None

IdRef

String

None

Type Sub-Element Attributes

Sub-Element <Column>

Element Type Column

Occurrence Range 0-unbounded

<Association>

Association

0-unbounded

<Type>
SubType

SubType

0-unbounded

This element represents a derived type in an inheritance hierarchy. This will be generated into a new CLR type with the columns and associations specified in this type. No inheritance attributes are generated for subtypes. Comparing to Type, SubType elements do not have AccessModifier because all derived types must be public. SubTypes cannot be reused by other tables and functions so there is no Id and IdRef in them. SubType Attributes

Attribute

Type

Default

Description

Name InheritanceCode

String String

(required) None

The name of the CLR type to be generated. If this type is participating in inheritance, it can have an associated inheritance code to distinguish between CLR types when loading rows from the table. The Type whose InheritanceCode matches the value of the IsDiscriminatorcolumn is used to instantiate the loaded object. If the inheritance code is not present, the generated entity class is abstract. If this is true for a Type in an inheritance hierarchy, this type will be used when loading rows that do not match on any defined inheritance codes. Description Represents a property within this type that will be bound to a field in this type's table. Represents a property within this type that will be bound to on one end of a foreign key relationship between tables. Represents subtypes of this type within an inheritance hierarchy.

IsInheritanceDefault

Boolean

False

SubType Sub-Element Attributes

Sub-Element <Column>

Element Type Column

Occurrence Range 0-unbounded

<Association>

Association

0-unbounded

<Type>
Column

SubType

0-unbounded

This element represents a column within a table that is mapped to a property (and backing field) within a class. There will be no Column element present for either end of a foreign key relationship, however, as that is completely represented (on both ends) by Association elements. Column Attributes

Attributes Name Member Storage

Type String String String

Default None Name _Member

Description The name of the database field this column will map to. The name of the CLR property to be generated on the containing type. The name of the private CLR backing field that will store this column's value. Do not remove Storage when serializing, even if it is default. The accessibility level of the CLR property being created. Valid values are: Public, Protected, Internal and Private.

AccessModifier AccessModifier Public

Type

String

(required)

The name of the type of both the CLR property and backing field being created. This may be anything from a fully qualified name to just the direct name of a class, as long as the name will ultimately be in scope when the generated code is compiled. Full SQL Server type (including annotation such as NOT NULL) for this column. Used by LINQ to SQL if you provide it to optimize the queries generated and to be more specific when doing CreateDatabase(). Always serialize DbType. If IsReadOnly is set, a property setter is not created, meaning people cannot change this column's value using that object. Indicates that this column participates in the primary key of the table. This information is required for LINQ to SQL to operate properly. Indicates that this field's data is generated by the database. This is the case primarily for AutoNumber fields, and for calculated fields. It is not meaningful to assign values to these fields, and therefore they are automatically IsReadOnly. Indicates that the value can contain the null value. If you wish to actually use null values in the CLR, you must still specify theClrType as Nullable<T>. Indicates whether LINQ to SQL should use this column during optimistic concurrency conflict detection. Normally all columns participate by default, unless there is an IsVersion column, which then participates by itself. Can be: Always, Never, orWhenChanged (which means the column participates if its own value has changed). Indicates whether this field contains the discriminator code used for choosing between types in an inheritance hierarchy. Does not affect LINQ to SQL's operation, but is used during .CreateDatabase() as a raw SQL expression representing the computed column expression. Indicates that this field represents a TIMESTAMP field in SQL Server that is automatically updated each time the row is

DbType

String

None

IsReadOnly

Boolean

False

IsPrimaryKey

Boolean

False

IsDbGenerated

Boolean

False

CanBeNull

Boolean

None

UpdateCheck

UpdateCheck

Always (unless at least one other member has IsVersionset, then Never)

IsDiscriminator Boolean

False

Expression

String

None

IsVersion

Boolean

False

changed. This field can then be used to enable more efficient optimistic concurrency conflict detection. IsDelayLoaded Boolean False Indicates that this column should not be loaded immediately upon object materialization, but only when the relevant property is first accessed. This is useful for large memo fields or binary data in a row that is not always needed. Specifies if the column is automatically synchronized from the value generated by the database. Valid values for this tag are:OnInsert, Always, and Never.

AutoSync

AutoSync

If (IsDbGenerated && IsPrimaryKey) OnInsert; Else if (IsDbGenerated) Always Else Never

Association This element represents either end of a foreign-key relationship. For one-to-many relationships, this will be an EntitySet<T> on the one side and an EntityRef<T>on the many side. For one-toone relationships, this will be an EntityRef<T> on both sides. Note that it is not required to have an Association entry on both sides of an association. In this case, a property will only be generated on the side that has the entry (forming a unidirectional relationship). Association Attributes

Attribute Name

Type String

Default (required)

Description The name of the relation (usually the foreign key constraint name). This can technically be optional, but should always be generated by code to avoid ambiguity when there are multiple relationships between the same two tables. The name of the CLR property to be generated on this side of the association.

Member Storage

String String

Name

AccessModifier

AccessModifier

If OneToMany The name of the private CLR backing field that and Not will store this column's value. IsForeignKey: _OtherTable Else: _TypeName(O therTable) Public The accessibility level of the CLR property being created. Valid values are Public, Protected, Internal and Private. The IsIdentity A comma separated list of the keys on this side property of the association.

ThisKey

String

within the containing class OtherTable String See description. The table on the other end of the relationship. Normally this can be determined by the LINQ to SQL runtime by matching relationship names, but this is not possible for unidirectional associations, or anonymous associations. A comma separated list of the keys on the other side of the association.

OtherKey

String

The primary keys within the foreign class False

IsForeignKey

Boolean

Indicates if this is the "child" side of the relationship, the many side of a one-to-many. Indicates whether the user is asserting that the data related to by this association meets the criteria of one-to-one data or fits the more general case of one-to-many. For one-to-one, the user is asserting that for every row on the primary-key ("one") side, there is only one row on the foreign-key ("many") side. This will cause an EntityRef<T> to be generated on the "one" side instead of an EntitySet<T>. The valid values areOneToOne and OneToMany. Used to add delete behavior to this association. For example, "CASCADE" would add "ON DELETE CASCADE" to the FK relationship. If set to null, no delete behavior is added.

RelationshipType RelationshipType OneToMany

DeleteRule

String

None

Function This element represents a stored procedure or a database function. For every Function node, a method is generated in the DataContext class. Function Attributes

Attribute Name Method

Type String String

Default Description (required) The name of the stored procedure within the database. Method The name of the CLR method to generate that allows invocation of the stored procedure. The default name forMethod has things such as [dbo]. stripped off Name. The accessibility level of the stored procedure method. Valid values are Public, Protected, Internal and Private.

AccessModifier

AccessModifier

Public

HasMultipleResults

Boolean

# of Types Specifies if the stored procedure represented by >1 thisFunction node returns multiple resultsets. Every resultset is a tabular shape, it can either be an existing Type or be a set of columns. In the latter case, a Type node will be created for the column set. False Specifies if the function/stored procedure can be composed in LINQ to SQL queries. Only DB functions that do not return void can be composed. Description Represents the in and out parameters of this stored procedure. Represents the tabular shapes the corresponding stored procedure can return. The returned scalar type of this db function or stored procedure. If Return is null, the function returns void. A function cannot have both Return and ElementType.

IsComposable

Boolean

Function Sub-Element Attributes

Sub-Element <Parameter> <ElementType> <Return>

Element Types Parameter Type Return

Occurrence Range 0-unbounded 0-unbounded 0-1

TableFunction This element represents CUD override functions for tables. The LINQ to SQL designer allows creation of Insert, Update, and Delete override methods for LINQ TO SQL and allows mapping of entity property names to stored procedure parameter names. The method name for CUD functions are fixed so there is no Method attribute in DBML for TableFunction elements. For example, for the Customer table, the CUD methods are named as InsertCustomer, UpdateCustomer, and DeleteCustomer. A table function cannot return tabular shape so there is no ElementType attribute in TableFunction element. TableFunction Attributes

Attribute Name AccessModifier

Type String AccessModifier

Default Description (required) The name of the stored procedure within the database. Private The accessibility level of the stored procedure method. Valid values are Public, Protected, Internal and Private.

HasMultipleResults

Boolean

# of Types Specifies if the stored procedure represented by >1 this Function node returns multiple resultsets. Every resultset is a tabular shape, it can either be an existing Type or be a set of columns. In the latter case, a Type node will be created for the column set. False Specifies if the function/stored procedure can be

IsComposable

Boolean

composed in LINQ to SQL queries. Only DB functions that do not return void can be composed.
TableFunction Sub-Element Attributes

Sub-Elements <Parameter>

Element Type TableFunctionParameter

Occurrence Range 0-unbounded

Description Represents the in and out parameters of this table function. The returned scalar type of this table function. IfReturn is null, the function returns void.

<Return>

TableFunctionReturn

0-1

Parameter This element represents a stored procedure/function parameter. Parameters can pass data in and out. Parameter Attributes

Attribute Name Parameter

Type String String String

Default (required) Name (required) None In

Descriptions The database name of the stored proc/function parameter. The CLR name of the method parameter. The CLR name of the method parameter. The DB type of the stored proc/function parameter. The direction that the parameter flows. Can be one of In, Out, andInOut.

DbType Direction

String ParameterDirection

Return This element represents the return type of a stored procedure/function. Return Attributes

Attribute Type DbType

Type String String

Default (required) None

Description The CLR type of the stored proc/function's result. The DB type of the stored proc/function's result.

TableFunctionParameter This element represents a parameter of a CUD function. Parameters can pass data in and out. Every parameter is mapped to a Table column that this CUD function belongs to. There is

no Type or DbType attributes in this element because type information can be obtained from the column to which the parameter maps. TableFunctionParameter Attributes

Attribute Name Parameter Column Direction Version

Type String String String ParameterDirection Version

Default (required) Name Name In Current

Description The database name of the CUD function parameter. The CLR name of the method parameter. The column name this parameter is mapping to. The direction that the parameter flows. Can be one of In, Out, orInOut. Whether PropertyName is referring to the current or original version of a given column. Only applicable during Updateoverride. Can be Current or Original.

TableFunctionReturn This element represents a return type of a CUD function. It actually only contains the column name that is mapped to the result of the CUD function. The type information of the return can be obtained from the column. TableFunctionReturn Attribute

Attrobite Column
Connection

Type String

Default None

Description The column name that the return is mapping to.

This element represents default database connection parameters. This allows the creation of a default constructor for the DataContext type that already knows how to connect to a database. There are two types of default connections possible, one with a direct ConnectionString, and one that reads from App.Settings. Connection Attributes

Attribute UseApplicationSettings

Type Boolean

Default False

Description Determines whether to use an App.Settings file or getApplication Settings from a direct ConnectionString. The connection string to send to the SQL data provider. The App.Settings Object to retrieve properties from. The App.Settings property that contains theConnectionString.

ConnectionString SettingsObjectName SettingsPropertyName

String String String

None Settings ConnectionString

Multi-tier Entities In two-tier applications, a single DataContext handles queries and updates. However, for applications with additional tiers, it is often necessary to use separateDataContext instances for query and updates. For example, in case of ASP.NET applications, query and update are done for separate requests to the Web server. Hence, it is impractical to use the same DataContext instance across multiple requests. In such cases, a DataContext instance needs to be able to update objects that it has not retrieved. The multi-tier entity support in LINQ to SQL provides such a capability through the Attach() method. Here is an example of how a Customer object can be changed using a different DataContext instance: C# // Customer entity changed on another tier for example, through a browser // Back on the mid-tier, a new context needs to be used Northwind db2 = new Northwind(); // Create a new entity for applying changes Customer C2 = new Customer(); C2.CustomerID ="NewCustID"; // Set other properties needed for optimistic concurrency check C2.CompanyName = "New Company Name Co."; ... // Tell LINQ to SQL to track this object for an update; that is, not for insertion db2.Customers.Attach(C2); // Now apply the changes C2.ContactName = "Mary Anders"; // DataContext now knows how to update the customer db2.SubmitChanges(); Visual Basic ' Customer entity changed on another tier for example, through a browser ' Back on the mid-tier, a new context needs to be used Dim db2 As Northwind = New Northwind() ' Create a new entity for applying changes Dim C2 As New Customer() C2.CustomerID =NewCustID ' Set other properties needed for optimistic concurrency check C2.CompanyName = New Company Name Co. ... ' Tell LINQ to SQL to track this object for an update; that is, not for insertion db2.Customers.Attach(C2) ' Now apply the changes C2.ContactName = "Mary Anders" ' DataContext now knows how to update the customer db2.SubmitChanges()

In multi-tier applications, the entire entity is often not sent across tiers for simplicity, interoperability, or privacy. For example, a supplier may define a data contract for a Web service that differs from the Order entity used on the middle tier. Likewise, a Web page may show only a subset of the members of an Employee entity. Hence, the multi-tier support is designed to accommodate such cases. Only the members belonging to one or more of the following categories need to be transported between tiers and set before calling Attach(). 1. Members that are part of the entity's identity. 2. Members that have been changed. 3. Members that participate in optimistic concurrency check. If a timestamp or a version number column is used for optimistic concurrency check, then the corresponding member must be set before calling Attach(). Values for other members need not be set before calling Attach(). LINQ to SQL uses minimal updates with optimistic concurrency checks; that is, a member that is not set or checked for optimistic concurrency is ignored. Original values required for optimistic concurrency checks may be retained using a variety of mechanisms outside the scope of LINQ to SQL APIs. An ASP.NET application may use a view state (or a control that uses the view state). A Web service may use the DataContract for an update method to ensure that the original values are available for update processing. In the interest of interoperability and generality, LINQ to SQL does not dictate the shape of the data exchanged between tiers or the mechanisms used for round-tripping the original values. Entities for insertion and deletion do not require the Attach() method. The methods used for twotier applicationsTable.Add() and Table.Remove() can be used for insertion and deletion. As in case of two-tier updates, a user is responsible for handling foreign key constraints. A customer with orders cannot be just removed without handling its orders if there is a foreign key constraint in the database preventing the deletion of a customer with orders. LINQ to SQL also handles attachment of entities for updates transitively. The user essentially creates the pre-update object graph as desired and calls Attach(). All changes can then be "replayed" on the attached graph to accomplish the necessary updates as shown below: C# Northwind db1 = new Northwind(); // Assume Customer c1 and related Orders o1, o2 are retrieved // Back on the mid-tier, a new context needs to be used Northwind db2 = new Northwind(); // Create new entities for applying changes Customer c2 = new Customer(); c2.CustomerID = c.CustomerID; Order o2 = new Order(); o2.OrderID = ...; c2.Orders.Add(o2); // Add other related objects needed for updates // Set properties needed for optimistic concurrency check ... // Order o1 to be deleted Order o1 = new Order(); o1.OrderID = ...; // Tell LINQ to SQL to track the graph transitively db2.Customers.Attach(c2); // Now "replay" all the changes

// Updates c2.ContactName = ...; o2.ShipAddress = ...; // New object for insertion Order o3 = new Order(); o3.OrderID = ...; c2.Orders.Add(o3); // Remove order o1 db2.Orders.Remove(o1); // DataContext now knows how to do update/insert/delete db2.SubmitChanges(); Visual Basic Dim db1 As Northwind = New Northwind() ' Assume Customer c1 and related Orders o1, o2 are retrieved ' Back on the mid-tier, a new context needs to be used Dim db2 As Northwind = New Northwind() ' Create new entities for applying changes Customer c2 = new Customer() c2.CustomerID = c.CustomerID Dim o2 As Order = New Order() o2.OrderID = ... c2.Orders.Add(o2) ' Add other related objects needed for updates ' Set properties needed for optimistic concurrency check ... ' Order o1 to be deleted Dim o1 As Order = New Order() o1.OrderID = ... ' Tell LINQ to SQL to track the graph transitively db2.Customers.Attach(c2) ' Now "replay" all the changes ' Updates c2.ContactName = ... o2.ShipAddress = ... ' New object for insertion Dim o3 As Order = New Order() o3.OrderID = ... c2.Orders.Add(o3) ' Remove order o1 db2.Orders.Remove(o1) ' DataContext now knows how to do update/insert/delete db2.SubmitChanges()

External Mapping In addition to attribute-based mapping, LINQ to SQL also supports external mapping. The most common form of external mapping is an XML file. Mapping files enable additional scenarios where separating mapping from code is desirable. DataContext provides an additional constructor for supplying a MappingSource. One form of MappingSource is an XmlMappingSource that can be constructed from an XML mapping file. Here is an example of how mapping file can be used: C# String path = @"C:\Mapping\NorthwindMapping.xml"; XmlMappingSource prodMapping = XmlMappingSource.FromXml(File.ReadAllText(path)); Northwind db = new Northwind( @"Server=.\SQLExpress;Database=c:\Northwind\Northwnd.mdf", prodMapping ); Visual Basic Dim path As String = "C:\Mapping\NorthwindMapping.xml" Dim prodMapping As XmlMappingSource = _ XmlMappingSource.FromXml(File.ReadAllText(path)) Dim db As Northwind = New Northwind( _ "Server=.\SQLExpress;Database=c:\Northwind\Northwnd.mdf", _ prodMapping ) Here is a corresponding snippet from the mapping file showing the mapping for Product class. It shows the class Product in namespace Mapping mapped to theProducts table in Northwind database. The elements and attributes are consistent with the attribute names and parameters. <?xml version="1.0" encoding="utf-8"?> <Database xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema" Name="Northwind" ProviderType="System.Data.Linq.SqlClient.Sql2005Provider"> <Table Name="Products"> <Type Name="Mappings.FunctionMapping.Product"> <Column Name="ProductID" Member="ProductID" Storage="_ProductID" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="True" IsDBGenerated="True" AutoSync="OnInsert" /> <Column Name="ProductName" Member="ProductName" Storage="_ProductName" DbType="NVarChar(40) NOT NULL" CanBeNull="False" /> <Column Name="SupplierID" Member="SupplierID" Storage="_SupplierID" DbType="Int" /> <Column Name="CategoryID" Member="CategoryID" Storage="_CategoryID" DbType="Int" /> <Column Name="QuantityPerUnit" Member="QuantityPerUnit" Storage="_QuantityPerUnit" DbType="NVarChar(20)" /> <Column Name="UnitPrice" Member="UnitPrice" Storage="_UnitPrice" DbType="Money" /> <Column Name="UnitsInStock" Member="UnitsInStock" Storage="_UnitsInStock" DbType="SmallInt" /> <Column Name="UnitsOnOrder" Member="UnitsOnOrder" Storage="_UnitsOnOrder" DbType="SmallInt" /> <Column Name="ReorderLevel" Member="ReorderLevel" Storage="_ReorderLevel" DbType="SmallInt" /> <Column Name="Discontinued" Member="Discontinued" Storage="_Discontinued" DbType="Bit NOT NULL" /> <Association Name="FK_Order_Details_Products" Member="OrderDetails"

Storage="_OrderDetails" ThisKey="ProductID" OtherTable="Order Details" OtherKey="ProductID" DeleteRule="NO ACTION" /> <Association Name="FK_Products_Categories" Member="Category" Storage="_Category" ThisKey="CategoryID" OtherTable="Categories" OtherKey="CategoryID" IsForeignKey="True" /> <Association Name="FK_Products_Suppliers" Member="Supplier" Storage="_Supplier" ThisKey="SupplierID" OtherTable="Suppliers" OtherKey="SupplierID" IsForeignKey="True" /> </Type> </Table> </Database> NET Framework Function Support and Notes The following paragraphs provide basic information regarding LINQ to SQL type support and differences from the .NET Framework. Primitive Types Implemented Arithmetic and comparison operators Shift operators: << and >> Conversion between char and numeric is done by UNICODE/NCHAR; otherwise SQL's CONVERT is used. Not implemented <Type>.Parse Enums can be used and mapped to integers and strings in a table. For the latter, the Parse and ToString() methods are used. Difference from .NET

The output of ToString for double uses CONVERT(NVARCHAR(30), @x, 2) on SQL, which
always uses 16 digits and "Scientific Notation." For example: "0.000000000000000e+000" for 0, so it does not give the same string as .NET's Convert.ToString(). System.String Implemented Non-static methods: Length, Substring, Contains, StartsWith, EndsWith, IndexOf, Insert, Remove , Replace, Trim, ToLower, ToUpper, LastIndexOf, PadRight, PadLeft,Equals, C ompareTo. All signatures are supported, except when they take the StringComparison parameter, and so on, as detailed below. Static methods: Concat(...) all signatures Compare(String, String) String (indexer) Equals(String, String) Constructor: String(Char, Int32) Operators: +, ==, != (+, =, and <> in Visual Basic) Not implemented Methods that take or produce an array of char.

Methods that take a CultureInfo/StringComparison/IFormatProvider.


Static (Shared in Visual Basic): Copy(String str) Compare(String, String, Boolean) Compare(String, String, StringComparison) Compare(String, String, Boolean, CultureInfo) Compare(String, Int32, String, Int32, Int32) Compare(String, Int32, String, Int32, Int32, Boolean) Compare(String, Int32, String, Int32, Int32, StringComparison) Compare(String, Int32, String, Int32, Int32, Boolean, CultureInfo) CompareOrdinal(String, String) CompareOrdinal(String, Int32, String, Int32, Int32) Join(String, ArrayOf String [,...]) All Join version with first three args Instance: ToUpperInvariant() Format(String, Object) + overloads IndexOf(String, Int32, StringComparison) IndexOfAny(ArrayOf Char) Normalize() Normalize(NormalizationForm) IsNormalized() Split(...) StartsWith(String, StringComparison) ToCharArray() ToUpper(CultureInfo) TrimEnd(ParamArray Char) TrimStart(ParamArray Char) Restrictions/Difference from .NET SQL uses collations to determine equality and ordering of strings. These can be specified on a SQL Server Instance, a database, a table column, or an expression. The translations of the functions implemented so far do not change the collation or specify a different collation on the translated expressions. So if the default collation is case-insensitive, functions like CompareTo or IndexOf can give results that differ from what the (case sensitive) .NET functions would give. The methods StartsWith(str)/EndsWith(str) assume the argument str is a constant or an expression that is evaluated on the client. That is, it is currently not possible to use a column for str. System.Math Implemented static methods All signatures: Abs, Acos, Asin, Atan, Atan2, BigMul, Ceiling, Cos, Cosh, Exp, Floor, Log, Log 10, Max, Min, Pow, Sign, Sinh, Sqrt, Tan, Tanh, or Truncate. Not implemented

IEEERemainder. DivRem has an out parameter, so you cannot use that in an expression. The
constants Math.PI and Math.E are evaluated on the client, so they do not need a translation. Difference from .NET The translation of the .NET function Math.Round is the SQL function ROUND. The translation is supported only when an overload is specified that indicates theMidpointRounding enum value.

The MidpointRounding.AwayFromZero is SQL behavior and MidpointRounding.ToEven indicates CLR behavior. System.Convert Implemented

Methods of form To<Type1>(<Type2> x) where Type1, Type2 is one of: bool, byte, char, DateTime, decimal, double, float, Int16, Int32, Int64,
or string. The behavior is the same as a cast: For ToString(Double) there is special code to get the full precision. For conversion Int32/Char, LINQ to SQL uses SQL's UNICODE/NCHAR function. Otherwise the translation is a CONVERT. Not Implemented

ToSByte, UInt16, 32, 64: These types do not exist in SQL.


To<integer type>(String, Int32) ToString(..., Int32) any overload ending with an Int32 toBase IsDBNull(Object) GetTypeCode(Object) ChangeType(...) Versions with the IFormatProvider parameter. Methods that involve an array (To/FromBase64CharArray, To/FromBase64String). System.TimeSpan Implemented Constructors: TimeSpan(Long) TimeSpan (year, month, day) TimeSpan (year, month, day, hour, minutes, seconds) TimeSpan (year, month, day, hour, minutes, seconds, milliseconds) Operators: Comparison operators: <,==, and so on in C#; <, =, and so on in Visual Basic +, Static (Shared in Visual Basic) methods: Compare(t1,t2) Non-static (Instance) methods / properties: Ticks, Milliseconds, Seconds, Hours, Days TotalMilliseconds, TotalSeconds, TotalMinutes, TotalHours, TotalDays, Equals, CompareTo(TimeSpan) Add(TimeSpan), Subtract(TimeSpan) Duration() [= ABS], Negate() Not implemented ToString() TimeSpan FromDay(Double), FromHours, all From Variants TimeSpan Parse(String) System.DateTime Implemented Constructors:

DateTime(year, month, day) DateTime(year, month, day, hour, minutes, seconds) DateTime(year, month, day, hour, minutes, seconds, milliseconds) Operators: Comparisons DateTime DateTime (gives TimeSpan) DateTime + TimeSpan (gives DateTime) DateTime TimeSpan (gives DateTime) Static (Shared) methods: Add(TimeSpan), AddTicks(Long), AddDays/Hours/Milliseconds/Minutes (Double) AddMonths/Years(Int32) Equals Non-static (Instance) methods / properties: Day, Month, Year, Hour, Minute, Second, Millisecond, DayOfWeek CompareTo(DateTime) TimeOfDay() Equals ToString() Difference from .NET SQL's datetime values are rounded to .000, .003 or .007 seconds, so it is less precise than those of .NET. The range of SQL's datetime starts at January 1st, 1753. SQL does not have a built-in type for TimeSpan. It uses different DATEDIFF methods that return 32-bit integers. One is DATEDIFF(DAY,...), which gives the number of days; another is DATEDIFF(MILLISECOND,...), which gives the number of milliseconds. An error results if the DateTimes are more than 24 days apart. In contrast, .NET uses 64-bit integers and measures TimeSpans in ticks. To get as close as possible to the .NET semantics in SQL, LINQ to SQL translates TimeSpans into 64-bit integers and uses the two DATEDIFF methods mentioned above to calculate the number of ticks between two dates. DateTime UtcNow is evaluated on the client when the query is translated (like any expression that does not involve database data). Not implemented IsDaylightSavingTime() IsLeapYear(Int32) DaysInMonth(Int32, Int32) ToBinary() ToFileTime() ToFileTimeUtc() ToLongDateString() ToLongTimeString() ToOADate() ToShortDateString() ToShortTimeString() ToUniversalTime() FromBinary(Long), FileTime, FileTimeUtc, OADate GetDateTimeFormats(...) constructor DateTime(Long) Parse(String) DayOfYear

Debugging Support DataContext provides methods and properties to obtain the SQL generated for queries and change processing. These methods can be useful for understanding LINQ to SQL functionality and for debugging specific problems. DataContext Methods to Get Generated SQL

Member Log

Purpose Prints SQL before it is executed. Covers query, insert, update, delete commands. Usage: C# db.Log = Console.Out; Visual Basic db.Log = Console.Out Returns the query text of the query without of executing it. Usage: C# Console.WriteLine(db.GetQueryText(db.Customers)); Visual Basic Console.WriteLine(db.GetQueryTest(db.Customers)) Returns the text of SQL commands for insert/update/delete without executing them. Usage: C# Console.WriteLine(db.GetChangeText()); Visual Basic Console.WriteLine(db.GetChangeText())

GetQueryText(query)

GetChangeText()

The .NET Standard Query Operators

Anders Hejlsberg, Mads Torgersen February 2007 Applies to: Visual Studio Code Name "Orcas" .Net Framework 3.5 Summary: The Standard Query Operators is an API that enables querying of any .NET array or collection. The Standard Query Operators API consists of the methods declared in the System.Query.Sequence static class in the assembly named System.Query.dll. (35 printed pages) Contents Technical Specification The Sequence Class Restriction Operators Projection Operators Partitioning Operators Join Operators Concatenation Operator Ordering Operators Grouping Operators

Set Operators Conversion Operators Equality Operator Element Operators Generation Operators Quantifiers Aggregate Operators Technical Specification The Standard Query Operators is an API that enables querying of any .NET array or collection. The Standard Query Operators API consists of the methods declared in the System.Query.Sequence static class in the assembly named System.Query.dll. The Standard Query Operators API complies with the .NET 2.0 Common Language Specification (CLS) and is usable with any .NET language that supports generics. While not required, the experience of using the Standard Query Operators is significantly enhanced with languages that support extension methods, lambda expressions, and native query syntax. The future releases of C# 3.0 and Visual Basic 9.0 will include these features. The Standard Query Operators operate on sequences. Any object that implements the interface IEnumerable<T> for some type T is considered a sequence of that type. The examples shown in this specification are all written in C# 3.0 and assume that the Standard Query Operators have been imported with the using clause: using System.Query; The examples refer to the following classes: public class Customer { public int CustomerID; public string Name; public string Address; public string City; public string Region; public string PostalCode; public string Country; public string Phone; public List<Order> Orders; } public class Order { public int OrderID; public int CustomerID; public Customer Customer; public DateTime OrderDate; public decimal Total; } public class Product { public int ProductID; public string Name; public string Category; public decimal UnitPrice; public int UnitsInStock; } The examples furthermore assume the existence of the following three variables: List<Customer> customers = GetCustomerList(); List<Order> orders = GetOrderList();

List<Product> products = GetProductList(); The Func Delegate Types The System.Query.Func family of generic delegate types can be used to construct delegate types "on the fly," thus eliminating the need for explicit delegate type declarations. public delegate TResult Func<TResult>(); public delegate TResult Func<TArg0, TResult>(TArg0 arg0); public delegate TResult Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1); public delegate TResult Func<TArg0, TArg1, TArg2, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2); public delegate TResult Func<TArg0, TArg1, TArg2, TArg3, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3); In each of the Func types, the TArg0, TArg1, TArg2, and TArg3 type parameters represent argument types and the TResult type parameter represents the result type. The example below declares a local variable predicate of a delegate type that takes a Customer and returns bool. The local variable is assigned an anonymous method that returns true if the given customer is located in London. The delegate referenced by predicate is subsequently used to find all the customers in London. Func<Customer, bool> predicate = c => c.City == "London"; IEnumerable<Customer> customersInLondon = customers.Where(predicate); The Sequence Class The System.Query.Sequence static class declares a set of methods known as the Standard Query Operators. The remaining sections of this chapter discuss these methods. The majority of the Standard Query Operators are extension methods that extend IEnumerable<T>. Taken together, the methods form a complete query language for arrays and collections that implement IEnumerable<T>. For further details on extension methods, please refer to the C# 3.0 and Visual Basic 9.0 Language Specifications. Restriction Operators Where The Where operator filters a sequence based on a predicate. public static IEnumerable<TSource> Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); public static IEnumerable<TSource> Where<TSource>( this IEnumerable<TSource> source, Func<TSource, int, bool> predicate); The Where operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if either argument is null. When the object returned by Where is enumerated, it enumerates the source sequence and yields those elements for which the predicate function returns true. The first argument of the predicate function represents the element to test. The second argument, if present, represents the zerobased index of the element within the source sequence. The following example creates a sequence of those products that have a price greater than or equal to 10: IEnumerable<Product> x = products.Where(p => p.UnitPrice >= 10);

In a C# 3.0 query expression, a where clause translates to an invocation of Where. The example above is equivalent to the translation of IEnumerable<Product> x = from p in products where p.UnitPrice >= 10 select p; Projection Operators Select The Select operator performs a projection over a sequence. public static IEnumerable<TResult> Select<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, TResult> selector); public static IEnumerable<TResult> Select<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, int, TResult> selector); The Select operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if either argument is null. When the object returned by Select is enumerated, it enumerates the source sequence and yields the results of evaluating the selector function for each element. The first argument of the selector function represents the element to process. The second argument, if present, represents the zerobased index of the element within the source sequence. The following example creates a sequence of the names of all products: IEnumerable<string> productNames = products.Select(p => p.Name); In a C# 3.0 query expression, a select clause translates to an invocation of Select. The example above is equivalent to the translation of IEnumerable<string> productNames = from p in products select p.Name; The following example creates a list of objects containing the name and price of each product with a price greater than or equal to 10: var namesAndPrices = products. Where(p => p.UnitPrice >= 10). Select(p => new { p.Name, p.UnitPrice }). ToList(); The following example creates a sequence of the indices of those products that have a price greater than or equal to 10: IEnumerable<int> indices = products. Select((product, index) => new { product, index }). Where(x => x.product.UnitPrice >= 10). Select(x => x.index); SelectMany The SelectMany operator performs a one-to-many element projection over a sequence. public static IEnumerable<TResult> SelectMany<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector); public static IEnumerable<TResult> SelectMany<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector);

public static IEnumerable<TResult> SelectMany<TOuter, TInner, TResult>( this IEnumerable<TOuter> source, Func<TOuter, IEnumerable<TInner>> selector, Func<TOuter, TInner, TResult> resultSelector); public static IEnumerable<TResult> SelectMany<TOuter, TInner, TResult>( this IEnumerable<TOuter> source, Func<TOuter, int, IEnumerable<TInner>> selector, Func<TOuter, TInner, TResult> resultSelector); The SelectMany operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if either argument is null. When the object returned by SelectMany is enumerated, it enumerates the source sequence, maps each element to an enumerable object using the selectorfunction, and enumerates the elements of each such enumerable object, yielding each if no resultSelector is given, or else passing each to the resultSelector along with the corresponding source element and yielding the resulting values. The first argument of the selector function represents the element to process. The second argument, if present, represents the zero-based index of the element within the source sequence. The following example creates a sequence of the orders of the customers in Denmark: IEnumerable<Order> orders = customers. Where(c => c.Country == "Denmark"). SelectMany(c => c.Orders); If the query had used Select instead of SelectMany, the result would have been of type IEnumerable<List<Order>> instead of IEnumerable<Order>. The following example creates a sequence of objects containing the customer name and order ID of the orders placed in 2005 by customers in Denmark: var namesAndOrderIDs = customers. Where(c => c.Country == "Denmark"). SelectMany(c => c.Orders). Where(o => o.OrderDate.Year == 2005). Select(o => new { o.Customer.Name, o.OrderID }); In the example above, the Customer property is used to "navigate back" to fetch the Name property of the order's customer. If an order had no Customerproperty (that is, if the relationship was unidirectional), an alternative solution is to rewrite the query, keeping the current customer, c, in scope such that it can be referenced in the final Select: var namesAndOrderIDs = customers. Where(c => c.Country == "Denmark"). SelectMany(c => c.Orders, (c,o) => new { c, o }). Where(co => co.o.OrderDate.Year == 2005). Select(co => new { co.c.Name, co.o.OrderID }); In a C# 3.0 query expression, all but the initial from clause translate to invocations of SelectMany. The example above is equivalent to the translation of var namesAndOrderIDs = from c in customers where c.Country == "Denmark" from o in c.Orders where o.OrderDate.Year == 2005 select new { c.Name, o.OrderID };

Partitioning Operators Take The Take operator yields a given number of elements from a sequence and then skips the remainder of the sequence. public static IEnumerable<TSource> Take<TSource>( this IEnumerable<TSource> source, int count); The Take operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if the source argument is null. When the object returned by Take is enumerated, it enumerates the source sequence and yields elements until the number of elements given by the count argument have been yielded or the end of the source is reached. If the count argument is less than or equal to zero, the source sequence is not enumerated and no elements are yielded. The Take and Skip operators are functional complements: For a given sequence s, the concatenation of s.Take(n) and s.Skip(n) yields the same sequence as s. The following example creates a sequence of the most expensive 10 products: IEnumerable<Product> MostExpensive10 = products.OrderByDescending(p => p.UnitPrice).Take(10); Skip The Skip operator skips a given number of elements from a sequence and then yields the remainder of the sequence. public static IEnumerable<TSource> Skip<TSource>( this IEnumerable<TSource> source, int count); The Skip operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if the source argument is null. When the object returned by Skip is enumerated, it enumerates the source sequence, skipping the number of elements given by the count argument and yielding the rest. If the source sequence contains fewer elements than the number given by the count argument, nothing is yielded. If the count argument is less than or equal to zero, all elements of the source sequence are yielded. The Take and Skip operators are functional complements: Given a sequence s, the concatenation of s.Take(n) and s.Skip(n) is the same sequence as s. The following example creates a sequence of all but the most expensive 10 products: IEnumerable<Product> AllButMostExpensive10 = products.OrderByDescending(p => p.UnitPrice).Skip(10); TakeWhile The TakeWhile operator yields elements from a sequence while a test is true and then skips the remainder of the sequence. public static IEnumerable<TSource> TakeWhile<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); public static IEnumerable<TSource> TakeWhile<TSource>( this IEnumerable<TSource> source, Func<TSource, int, bool> predicate); The TakeWhile operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if either argument is null.

When the object returned by TakeWhile is enumerated, it enumerates the source sequence, testing each element using the predicate function and yielding the element if the result was true. The enumeration stops when the predicate function returns false or the end of the source sequence is reached. The first argument of the predicate function represents the element to test. The second argument, if present, represents the zero-based index of the element within the source sequence. The TakeWhile and SkipWhile operators are functional complements: Given a sequence s and a pure function p, the concatenation of s.TakeWhile(p) ands.SkipWhile(p) is the same sequence as s. SkipWhile The SkipWhile operator skips elements from a sequence while a test is true and then yields the remainder of the sequence. public static IEnumerable<TSource> SkipWhile<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); public static IEnumerable<TSource> SkipWhile<TSource>( this IEnumerable<TSource> source, Func<TSource, int, bool> predicate); The SkipWhile operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if either argument is null. When the object returned by SkipWhile is enumerated, it enumerates the source sequence, testing each element using the predicate function and skipping the element if the result was true. Once the predicate function returns false for an element, that element and the remaining elements are yielded with no further invocations of the predicate function. If the predicate function returns true for all elements in the sequence, no elements are yielded. The first argument of the predicate function represents the element to test. The second argument, if present, represents the zero-based index of the element within the source sequence. The TakeWhile and SkipWhile operators are functional complements: Given a sequence s and a pure function p, the concatenation of s.TakeWhile(p) ands.SkipWhile(p) is the same sequence as s. Join Operators Join The Join operator performs an inner join of two sequences based on matching keys extracted from the elements. public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector); public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer); The Join operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if any argument is null.

The outerKeySelector and innerKeySelector arguments specify functions that extract the join key values from elements of the outer and inner sequences, respectively. The resultSelector argument specifies a function that creates a result element from two matching outer and inner sequence elements. When the object returned by Join is enumerated, it first enumerates the inner sequence and evaluates the innerKeySelector function once for each inner element, collecting the elements by their keys in a hash table. Once all inner elements and keys have been collected, the outer sequence is enumerated. For each outer element, the outerKeySelector function is evaluated and, if non-null, the resulting key is used to look up the corresponding inner elements in the hash table. For each matching inner element (if any), the resultSelector function is evaluated for the outer and inner element pair, and the resulting object is yielded. If a non-null comparer argument is supplied, it is used to hash and compare the keys. Otherwise the default equality comparer, EqualityComparer<TKey>.Default, is used. The Join operator preserves the order of the outer sequence elements, and for each outer element, the order of the matching inner sequence elements. In relational database terms, the Join operator implements an inner equijoin. Other join operations, such as left outer join and right outer join, have no dedicated standard query operators, but are subsets of the capabilities of the GroupJoin operator. The following example joins customers and orders on their customer ID property, producing a sequence of tuples with customer name, order date, and order total: var custOrders = customers. Join(orders, c => c.CustomerID, o => o.CustomerID, (c, o) => new { c.Name, o.OrderDate, o.Total } ); In a C# 3.0 query expression, a join clause translates to an invocation of Join. The example above is equivalent to the translation of var custOrders = from c in customers join o in orders on c.CustomerID equals o.CustomerID select new { c.Name, o.OrderDate, o.Total }; GroupJoin The GroupJoin operator performs a grouped join of two sequences based on matching keys extracted from the elements. public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector); public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer); The GroupJoin operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if any argument is null.

The outerKeySelector and innerKeySelector arguments specify functions that extract the join key values from elements of the outer and inner sequences, respectively. The resultSelector argument specifies a function that creates a result element from an outer sequence element and its matching inner sequence elements. When the object returned by GroupJoin is enumerated, it first enumerates the inner sequence and evaluates the innerKeySelector function once for each inner element, collecting the elements by their keys in a hash table. Once all inner elements and keys have been collected, the outer sequence is enumerated. For each outer element, the outerKeySelector function is evaluated, the resulting key is used to look up the corresponding inner elements in the hash table, theresultSelector function is evaluated for the outer element and the (possibly empty) sequence of matching inner elements, and the resulting object is yielded. If a non-null comparer argument is supplied, it is used to hash and compare the keys. Otherwise the default equality comparer, EqualityComparer<TKey>.Default, is used. The GroupJoin operator preserves the order of the outer sequence elements, and for each outer element, it preserves the order of the matching inner sequence elements. The GroupJoin operator produces hierarchical results (outer elements paired with sequences of matching inner elements) and has no direct equivalent in traditional relational database terms. The following example performs a grouped join of customers with their orders, producing a sequence of tuples with customer name and total of all orders: var custTotalOrders = customers. GroupJoin(orders, c => c.CustomerID, o => o.CustomerID, (c, co) => new { c.Name, TotalOrders = co.Sum(o => o.Total) } ); In a C# 3.0 query expression, a join...into clause translates to an invocation of GroupJoin. The example above is equivalent to the translation of: var custTotalOrders = from c in customers join o in orders on c.CustomerID equals o.CustomerID into co select new { c.Name, TotalOrders = co.Sum(o => o.Total) }; The GroupJoin operator implements a superset of inner joins and left outer joinsboth can be written in terms of grouped joins. For example, the inner join: var custTotalOrders = from c in customers join o in orders on c.CustomerID equals o.CustomerID select new { c.Name, o.OrderDate, o.Total }; can be written as a grouped join followed by an iteration of the grouped orders: var custTotalOrders = from c in customers join o in orders on c.CustomerID equals o.CustomerID into co from o in co select new { c.Name, o.OrderDate, o.Total }; You can turn the query into a left outer join by applying the DefaultIfEmpty operator to the grouped orders var custTotalOrders = from c in customers join o in orders on c.CustomerID equals o.CustomerID into co from o in co.DefaultIfEmpty(emptyOrder) select new { c.Name, o.OrderDate, o.Total }; where emptyOrder is an Order instance used to represent a missing order.

Concatenation Operator Concat The Concat operator concatenates two sequences. public static IEnumerable<TSource> Concat<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second); The Concat operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if either argument is null. When the object returned by Concat is enumerated, it enumerates the first sequence, yielding each element, and then it enumerates the second sequence, yielding each element. The following example extracts all distinct locations from the addresses of all customers: IEnumerable<string> locations = customers.Select(c => c.City). Concat(customers.Select(c => c.Region)). Concat(customers.Select(c => c.Country)). Distinct(); An alternative way of concatenating sequences is to construct a sequence of sequences (such as an array of sequences) and apply the SelectMany operator with an identity selector function. For example: IEnumerable<string> locations = new[] { customers.Select(c => c.City), customers.Select(c => c.Region), customers.Select(c => c.Country), }. SelectMany(s => s). Distinct(); Ordering Operators OrderBy and ThenBy Operators in the OrderBy/ThenBy family of operators order a sequence according to one or more keys. public static OrderedSequence<TSource> OrderBy<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static OrderedSequence<TSource> OrderBy<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer); public static OrderedSequence<TSource> OrderByDescending<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static OrderedSequence<TSource> OrderByDescending<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer); public static OrderedSequence<TSource> ThenBy<TSource, TKey>( this OrderedSequence<TSource> source, Func<TSource, TKey> keySelector); public static OrderedSequence<TSource> ThenBy<TSource, TKey>( this OrderedSequence<TSource> source,

Func<TSource, TKey> keySelector, IComparer<TKey> comparer); public static OrderedSequence<TSource> ThenByDescending<TSource, TKey>( this OrderedSequence<TSource> source, Func<TSource, TKey> keySelector); public static OrderedSequence<TSource> ThenByDescending<TSource, TKey>( this OrderedSequence<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer); The OrderBy, OrderByDescending, ThenBy, and ThenByDescending operators make up a family of operators that can be composed to order a sequence by multiple keys. A composition of the operators has the form source . OrderBy(...) . ThenBy(...) . ThenBy(...) ... where OrderBy(...) is an invocation of OrderBy or OrderByDescending and each ThenBy(...), if any, is an invocation of ThenBy or ThenByDescending. The initialOrderBy or OrderByDescending establishes the primary ordering, the first ThenBy or ThenByDescending establishes the secondary ordering, the secondThenBy or ThenByDescending establishes the tertiary ordering, and so on. Each ordering is defined by:

A keySelector function that extracts the key value, of type TKey, from an element, of
type TSource. An optional comparer for comparing key values. If no comparer is specified or if the comparer argument is null, the default comparer,Comparer<TKey>.Default, is used. A sort direction. The OrderBy and ThenBy methods establish an ascending ordering, the OrderByDescending and ThenByDescending methods establish a descending ordering. An invocation of OrderBy, OrderByDescending, ThenBy, or ThenByDescending allocates and returns an enumerable object of type OrderedSequence<TSource>that captures the arguments passed to the operator. An ArgumentNullException is thrown if the source or keySelector argument is null. TheOrderedSequence<TElement> class implements IEnumerable<TElement>, but otherwise introduces no public members. When the object returned by one of the operators is enumerated, it first enumerates source, collecting all elements. It then evaluates the keySelector function(s) once for each element, collecting the key values to order by. It then sorts the elements according to the collected key values and the characteristics of each ordering. Finally, it yields the elements in the resulting order. Calling OrderBy or OrderByDescending on the result of an OrderBy/ThenBy operator will introduce a new primary ordering, disregarding the previously established ordering. The OrderBy/ThenBy operators perform a stable sort; that is, if the key values of two elements are equal, the order of the elements is preserved. In contrast, an unstable sort does not preserve the order of elements that have equal key values. The following example creates a sequence of all products, ordered first by category, then by descending price, and then by name. IEnumerable<Product> orderedProducts1 = products. OrderBy(p => p.Category). ThenByDescending(p => p.UnitPrice). ThenBy(p => p.Name); In a C# 3.0 query expression, an orderby clause translates to invocations of OrderBy, OrderByDescending, ThenBy, and ThenByDescending. The example above is equivalent to the translation of IEnumerable<Product> orderedProducts1 =

from p in products orderby p.Category, p.UnitPrice descending, p.Name select p; The following example creates a sequence of all beverage products ordered by case insensitive name: IEnumerable<Product> orderedProducts2 = products. Where(p => p.Category == "Beverages"). OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase); To order a sequence by the values of the elements themselves, specify the identity key selector x => x. For example: IEnumerable<string> orderedProductNames = products. Where(p => p.Category == "Beverages"). Select(p => p.Name). OrderBy(x => x); Reverse The Reverse operator reverses the elements of a sequence. public static IEnumerable<TSource> Reverse<TSource>( this IEnumerable<TSource> source); The Reverse operator allocates and returns an enumerable object that captures the source argument. An ArgumentNullException is thrown if the source argument is null. When the object returned by Reverse is enumerated, it enumerates the source sequence, collecting all elements, and then yields the elements of the source sequence in reverse order. Grouping Operators GroupBy The GroupBy operator groups the elements of a sequence. public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer); public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector); public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer); public interface IGrouping<TKey, TElement> : IEnumerable<TElement> { TKey Key { get; }

} The GroupBy operator allocates and returns an enumerable object that captures the arguments passed to the operator. The comparer argument, if present, may be null. An ArgumentNullException is thrown if any other argument is null. The keySelector argument specifies a function that extracts the key value from a source element. The elementSelector argument, if present, specifies a function that maps a source element to a destination element. If no elementSelector is specified, the source elements become the destination elements. When the object returned by GroupBy is enumerated, it enumerates source and evaluates the keySelector and elementSelector (if present) functions once for each source element. Once all key and destination element pairs have been collected, a sequence of IGrouping<TKey, TElement> instances are yielded. EachIGrouping<TKey, TElement> instance represents a sequence of destination elements with a particular key value. The groupings are yielded in the order in which their key values first occurred in the source sequence, and destination elements within a grouping are yielded in the order in which their source elements occurred in the source sequence. When creating the groupings, key values are compared using the given comparer, or, if a null comparer was specified, using the default equality comparer, EqualityComparer<TKey>.Default. The following example groups all products by category: IEnumerable<IGrouping<string, Product>> productsByCategory = products.GroupBy(p => p.Category); The following example groups all product names by product category: IEnumerable<IGrouping<string, string>> productNamesByCategory = products.GroupBy(p => p.Category, p => p.Name); In a C# 3.0 query expression, a group...by clause translates to an invocation of GroupBy. The example above is equivalent to the translation of IEnumerable<IGrouping<string, string>> productNamesByCategory = from p in products group p.Name by p.Category; Note that the element and key selection expressions occur in the opposite order of the GroupBy operator. Set Operators Distinct The Distinct operator eliminates duplicate elements from a sequence. public static IEnumerable<TSource> Distinct<TSource>( this IEnumerable<TSource> source); public static IEnumerable<TSource> Distinct<TSource>( this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer); The Distinct operator allocates and returns an enumerable object that captures the source argument. An ArgumentNullException is thrown if the source argument is null. When the object returned by Distinct is enumerated, it enumerates the source sequence, yielding each element that has not previously been yielded. If a non-nullcomparer argument is supplied, it is used to compare the elements. Otherwise the default equality comparer, EqualityComparer<TSource>.Default, is used. The following example produces a sequence of all product categories: IEnumerable<string> productCategories = products.Select(p => p.Category).Distinct();

Union The Union operator produces the set union of two sequences. public static IEnumerable<TSource> Union<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second); public static IEnumerable<TSource> Union<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer); The Union operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if any argument is null. When the object returned by Union is enumerated, it enumerates the first and second sequences, in that order, yielding each element that has not previously been yielded. If a nonnull comparer argument is supplied, it is used to compare the elements. Otherwise the default equality comparer,EqualityComparer<TSource>.Default, is used. Intersect The Intersect operator produces the set intersection of two sequences. public static IEnumerable<TSource> Intersect<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second); public static IEnumerable<TSource> Intersect<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer); The Intersect operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if any argument is null. When the object returned by Intersect is enumerated, it enumerates the first sequence, collecting all distinct elements of that sequence. It then enumerates the second sequence, marking those elements that occur in both sequences. It finally yields the marked elements in the order in which they were collected. If a non-nullcomparer argument is supplied, it is used to compare the elements. Otherwise the default equality comparer, EqualityComparer<TSource>.Default, is used. Except The Except operator produces the set difference between two sequences. public static IEnumerable<TSource> Except<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second); public static IEnumerable<TSource> Except<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer); The Except operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if any argument is null. When the object returned by Except is enumerated, it enumerates the first sequence, collecting all distinct elements of that sequence. It then enumerates the second sequence, removing those elements that were also contained in the first sequence. It finally yields the remaining elements in the order in which they were collected. If a non-null comparer argument is supplied, it is used to compare the elements. Otherwise the default equality comparer, EqualityComparer<TSource>.Default, is used.

Conversion Operators AsEnumerable The AsEnumerable operator returns its argument typed as IEnumerable<TSource>. public static IEnumerable<TSource> AsEnumerable<TSource>( this IEnumerable<TSource> source); The AsEnumerable operator simply returns the source argument. The operator has no effect other than to change the compile-time type of the source argument to IEnumerable<TSource>. The AsEnumerable operator can be used to choose between query operator implementations in cases where a collection implements IEnumerable<T> but also has a different set of public query operators. For example, given a class Table<T> that implements IEnumerable<T> as well as its own Where, Select,SelectMany, and so on, the query Table<Customer> custTable = GetCustomersTable(); var query = custTable.Where(c => IsGoodCustomer(c)); will invoke the public Where operator of Table<T>. A Table<T> type that represents a database table would likely have a Where operator that takes the predicate argument as an expression tree and converts the tree into SQL for remote execution. If remote execution is not desired, for example because the predicate invokes a local method, the AsEnumerable operator can be used to hide Table<T>'s operators and instead make the Standard Query Operators available: Table<Customer> custTable = GetCustomersTable(); var query = custTable.AsEnumerable().Where(c => IsGoodCustomer(c)); This would cause the query to execute locally. ToArray The ToArray operator creates an array from a sequence. public static TSource[] ToArray<TSource>( this IEnumerable<TSource> source); The ToArray operator enumerates the source sequence and returns an array containing the elements of the sequence. An ArgumentNullException is thrown if the source argument is null. The following example produces an array of the names of all countries in which there are customers: string[] customerCountries = customers.Select(c => c.Country).Distinct().ToArray(); ToList The ToList operator creates a List<TSource> from a sequence. public static List<TSource> ToList<TSource>( this IEnumerable<TSource> source); The ToList operator enumerates the source sequence and returns a List<TSource> containing the elements of the sequence. An ArgumentNullException is thrown if the source argument is null. The following example produces a List<Customer> containing those customers that placed orders in 2005: List<Customer> customersWithOrdersIn2005 = customers. Where(c => c.Orders.Any(o => o.OrderDate.Year == 2005)). ToList();

ToDictionary The ToDictionary operator creates a Dictionary<TKey,TElement> from a sequence. public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer); public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector); public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer); The ToDictionary operator enumerates the source sequence and evaluates the keySelector and elementSelector functions for each element to produce that element's key and value. The resulting key and value pairs are returned in a Dictionary<TKey,TElement>. If no elementSelector was specified, the value for each element is simply the element itself. An ArgumentNullException is thrown if the source, keySelector, or elementSelector argument is null or if a key value produced by keySelector is null. An ArgumentException is thrown if keySelector produces a duplicate key value for two elements. In the resulting dictionary, key values are compared using the given comparer, or, if a null comparer was specified, using the default equality comparer, EqualityComparer<TKey>.Default. The following example creates a Dictionary<int,Order> that maps from order ID to order for all orders in 2005: Dictionary<int,Order> orders = customers. SelectMany(c => c.Orders). Where(o => o.OrderDate.Year == 2005). ToDictionary(o => o.OrderID); The following example creates a Dictionary<string,decimal> that maps from category name to the maximum product price in that category: Dictionary<string,decimal> categoryMaxPrice = products. GroupBy(p => p.Category). ToDictionary(g => g.Key, g => g.Group.Max(p => p.UnitPrice)); ToLookup The ToLookup operator creates a Lookup<TKey, TElement> from a sequence. public static Lookup<TKey, TSource> ToLookup<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static Lookup<TKey, TSource> ToLookup<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer); public static Lookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(

this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector); public static Lookup<TKey, TElement> ToLookup<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer); public class Lookup<TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>> { public int Count { get; } public IEnumerable<TElement> this[TKey key] { get; } public bool Contains(TKey key); public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator(); } Lookup<TKey, TElement> implements a one-to-many dictionary that maps keys to sequences of values. This differs from Dictionary<TKey, TElement>, which implements a one-to-one dictionary that maps keys to single values. The functionality provided by Lookup<TKey, TElement> is used in the implementations of theJoin, GroupJoin, and GroupBy operators. The ToLookup operator enumerates the source sequence and evaluates the keySelector and elementSelector functions for each element to produce that element's key and value. The resulting key and value pairs are returned in a Lookup<TKey, TElement>. If no elementSelector was specified, the value for each element is simply the element itself. An ArgumentNullException is thrown if the source, keySelector, or elementSelector argument is null. When creating theLookup<TKey, TElement>, key values are compared using the given comparer, or, if a null comparer was specified, using the default equality comparer,EqualityComparer<TKey>.Default. The following example creates a Lookup<string, Product> that maps from category name to the sequence of products in that category: Lookup<string,Product> productsByCategory = products.ToLookup(p => p.Category); IEnumerable<Product> beverages = productsByCategory["Beverage"]; OfType The OfType operator filters the elements of a sequence based on a type. public static IEnumerable<TResult> OfType<TResult>( this IEnumerable source); The OfType operator allocates and returns an enumerable object that captures the source argument. An ArgumentNullException is thrown if the source argument is null. When the object returned by OfType is enumerated, it enumerates the source sequence and yields those elements that are of type TResult. Specifically, each element e for which e is TResult evaluates to true is yielded by evaluating (TResult)e. Given a class Employee that inherits from a class Person, the following example returns all employees from a list of persons: List<Person> persons = GetListOfPersons(); IEnumerable<Employee> employees = persons.OfType<Employee>(); Cast The Cast operator casts the elements of a sequence to a given type. public static IEnumerable<TResult> Cast<TResult>( this IEnumerable source);

The Cast operator allocates and returns an enumerable object that captures the source argument. An ArgumentNullException is thrown if the source argument is null. When the object returned by Cast is enumerated, it enumerates the source sequence and yields each element cast to type TResult. An InvalidCastException is thrown if an element in the sequence cannot be cast to type TResult. The Cast operator can be used to bridge between non-generic collections and the Standard Query Operators. For example, the non-generic ArrayList does not implement IEnumerable<TResult>, but the Cast operator can be used to supply the missing type information: ArrayList objects = GetOrders(); IEnumerable<Order> ordersIn2005 = objects. Cast<Order>(). Where(o => o.OrderDate.Year == 2005); In a C# 3.0 query expression, an explicitly typed iteration variable translates to an invocation of Cast. The example above is equivalent to the translation of: ArrayList objects = GetOrders(); IEnumerable<Order> ordersIn2005 = from Order o in objects where o.OrderDate.Year == 2005 select o; Equality Operator SequenceEqual The SequenceEqual operator checks whether two sequences are equal. public static bool SequenceEqual<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second); public static bool SequenceEqual<TSource>( this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer); The SequenceEqual operator enumerates the two source sequences in parallel and compares corresponding elements. If a non-null comparer argument is supplied, it is used to compare the elements. Otherwise the default equality comparer, EqualityComparer<TSource>.Default, is used. The method returns true if all corresponding elements compare equal and the two sequences are of equal length. Otherwise, the method returns false. An ArgumentNullException is thrown if either argument is null. Element Operators First The First operator returns the first element of a sequence. public static TSource First<TSource>( this IEnumerable<TSource> source); public static TSource First<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The First operator enumerates the source sequence and returns the first element for which the predicate function returns true. If no predicate function is specified, the First operator simply returns the first element of the sequence.

An ArgumentNullException is thrown if any argument is null. An InvalidOperationException is thrown if no element matches the predicate or if the source sequence is empty. The following example returns the first customer with a given phone number: string phone = "206-555-1212"; Customer c = customers.First(c => c.Phone == phone); In the example above, an exception is thrown if no customer with the given phone number exists. To instead return a default value when no element is found, use the FirstOrDefault operator. FirstOrDefault The FirstOrDefault operator returns the first element of a sequence, or a default value if no element is found. public static TSource FirstOrDefault<TSource>( this IEnumerable<TSource> source); public static TSource FirstOrDefault<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The FirstOrDefault operator enumerates the source sequence and returns the first element for which the predicate function returns true. If no predicate function is specified, the FirstOrDefault operator simply returns the first element of the sequence. An ArgumentNullException is thrown if any argument is null. If no element matches the predicate or if the source sequence is empty, default(TSource) is returned. The default value for reference and nullable types is null. Last The Last operator returns the last element of a sequence. public static TSource Last<TSource>( this IEnumerable<TSource> source); public static TSource Last<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The Last operator enumerates the source sequence and returns the last element for which the predicate function returned true. If no predicate function is specified, the Last operator simply returns the last element of the sequence. An ArgumentNullException is thrown if any argument is null. An InvalidOperationException is thrown if no element matches the predicate or if the source sequence is empty. LastOrDefault The LastOrDefault operator returns the last element of a sequence, or a default value if no element is found. public static TSource LastOrDefault<TSource>( this IEnumerable<TSource> source); public static TSource LastOrDefault<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The LastOrDefault operator enumerates the source sequence and returns the last element for which the predicate function returned true. If no predicate function is specified, the LastOrDefault operator simply returns the last element of the sequence.

An ArgumentNullException is thrown if any argument is null. If no element matches the predicate or if the source sequence is empty, default(TSource) is returned. The default value for reference and nullable types is null. Single The Single operator returns the single element of a sequence. public static TSource Single<TSource>( this IEnumerable<TSource> source); public static TSource Single<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The Single operator enumerates the source sequence and returns the single element for which the predicate function returned true. If no predicate function is specified, the Single operator simply returns the single element of the sequence. An ArgumentNullException is thrown if any argument is null. An InvalidOperationException is thrown if the source sequence contains no matching element or more than one matching element. The following example returns the single customer with a given customer ID: int id = 12345; Customer c = customers.Single(c => c.CustomerID == id); In the example above, an exception is thrown if no customer or more than one customer with the given ID exists. To instead return null when no element is found, use the SingleOrDefault operator. SingleOrDefault The SingleOrDefault operator returns the single element of a sequence, or a default value if no element is found. public static TSource SingleOrDefault<TSource>( this IEnumerable<TSource> source); public static TSource SingleOrDefault<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The SingleOrDefault operator enumerates the source sequence and returns the single element for which the predicate function returned true. If no predicate function is specified, the SingleOrDefault operator simply returns the single element of the sequence. An ArgumentNullException is thrown if any argument is null. An InvalidOperationException is thrown if the source sequence contains more than one matching element. If no element matches the predicate or if the source sequence is empty, default(TSource) is returned. The default value for reference and nullable types is null. ElementAt The ElementAt operator returns the element at a given index in a sequence. public static TSource ElementAt<TSource>( this IEnumerable<TSource> source, int index); The ElementAt operator first checks whether the source sequence implements IList<TSource>. If it does, the source sequence's implementation of IList<TSource>is used to obtain the element at the given index. Otherwise, the source sequence is enumerated until index elements have been skipped, and the element found at that position in the sequence is returned. An ArgumentNullException is thrown if the source argument is null.

An ArgumentOutOfRangeException is thrown if the index is less than zero or greater than or equal to the number of elements in the sequence. The following example obtains the third most expensive product: Product thirdMostExpensive = products.OrderByDescending(p => p.UnitPrice).ElementAt(2); ElementAtOrDefault The ElementAtOrDefault operator returns the element at a given index in a sequence, or a default value if the index is out of range. public static TSource ElementAtOrDefault<TSource>( this IEnumerable<TSource> source, int index); The ElementAtOrDefault operator first checks whether the source sequence implements IList<TSource>. If it does, the source sequence's implementation ofIList<TSource> is used to obtain the element at the given index. Otherwise, the source sequence is enumerated until index elements have been skipped, and the element found at that position in the sequence is returned. An ArgumentNullException is thrown if the source argument is null. If the index is less than zero or greater than or equal to the number of elements in the sequence, default(TSource) is returned. The default value for reference and nullable types is null. DefaultIfEmpty The DefaultIfEmpty operator supplies a default element for an empty sequence. public static IEnumerable<TSource> DefaultIfEmpty<TSource>( this IEnumerable<TSource> source); public static IEnumerable<TSource> DefaultIfEmpty<TSource>( this IEnumerable<TSource> source, TSource defaultValue); The DefaultIfEmpty operator allocates and returns an enumerable object that captures the arguments passed to the operator. An ArgumentNullException is thrown if the source argument is null. When the object returned by DefaultIfEmpty is enumerated, it enumerates the source sequence and yields its elements. If the source sequence is empty, a single element with the given default value is yielded. If no default value argument is specified, default(TSource) is yielded in place of an empty sequence. The default value for reference and nullable types is null. The DefaultIfEmpty operator can be combined with a grouping join to produce a left outer join. See the GroupJoin section of this document for an example. Generation Operators Range The Range operator generates a sequence of integral numbers. public static IEnumerable<int> Range( int start, int count); The Range operator allocates and returns an enumerable object that captures the arguments. An ArgumentOutOfRangeException is thrown if count is less than zero or if start + count 1 is larger than int.MaxValue. When the object returned by Range is enumerated, it yields count sequential integers starting with the value start. The following example produces an array of the squares of the numbers from 0 to 99:

int[] squares = Sequence.Range(0, 100).Select(x => x * x).ToArray(); Repeat The Repeat operator generates a sequence by repeating a value a given number of times. public static IEnumerable<TResult> Repeat<TResult>( TResult element, int count); The Repeat operator allocates and returns an enumerable object that captures the arguments. An ArgumentOutOfRangeException is thrown if the specified count is less than zero. When the object returned by Repeat is enumerated, it yields count occurrences of element. The following example produces a long[] with 256 elements containing the value -1. long[] x = Sequence.Repeat(-1L, 256).ToArray(); Empty The Empty operator returns an empty sequence of a given type. public static IEnumerable<TResult> Empty<TResult>(); The Empty operator caches a single empty sequence of the given type. When the object returned by Empty is enumerated, it yields nothing. The following obtains an empty sequence of customers: IEnumerable<Customer> noCustomers = Sequence.Empty<Customer>(); Quantifiers Any The Any operator checks whether any element of a sequence satisfies a condition. public static bool Any<TSource>( this IEnumerable<TSource> source); public static bool Any<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The Any operator enumerates the source sequence and returns true if any element satisfies the test given by the predicate. If no predicate function is specified, theAny operator simply returns true if the source sequence contains any elements. The enumeration of the source sequence is terminated as soon as the result is known. An ArgumentNullException is thrown if any argument is null. The following example checks whether any products with a price of 100 or more are out of stock. bool b = products.Any(p => p.UnitPrice >= 100 && p.UnitsInStock == 0); All The All operator checks whether all elements of a sequence satisfy a condition. public static bool All<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The All operator enumerates the source sequence and returns true if no element fails the test given by the predicate. The enumeration of the source sequence is terminated as soon as the result is known. An ArgumentNullException is thrown if any argument is null.

The All operator returns true for an empty sequence. This is consistent with established predicate logic and other query languages such as SQL. The following example produces the names of the product categories for which all products are in stock: IEnumerable<string> fullyStockedCategories = products. GroupBy(p => p.Category). Where(g => g.Group.All(p => p.UnitsInStock > 0)). Select(g => g.Key); Contains The Contains operator checks whether a sequence contains a given element. public static bool Contains<TSource>( this IEnumerable<TSource> source, TSource value); public static bool Contains<TSource>( this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer); The Contains operator first checks whether the source sequence implements ICollection<TSource>. If it does, the Contains method in sequence's implementation of ICollection<TSource> is invoked to obtain the result. Otherwise, the source sequence is enumerated to determine if it contains an element with the given value. If a matching element is found, the enumeration of the source sequence is terminated at that point. If a nonnull comparer argument is supplied, it is used to compare the elements to the given value. Otherwise the default equality comparer, EqualityComparer<TSource>.Default, is used. An ArgumentNullException is thrown if the source argument is null. Aggregate Operators Count The Count operator counts the number of elements in a sequence. public static int Count<TSource>( this IEnumerable<TSource> source); public static int Count<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The Count operator without a predicate first checks whether the source sequence implements ICollection<TSource>. If it does, the sequence's implementation ofICollection<TSource> is used to obtain the element count. Otherwise, the source sequence is enumerated to count the number of elements. The Count operator with a predicate enumerates the source sequence and counts the number of elements for which the predicate function returns true. For both Count operators, an ArgumentNullException is thrown if any argument is null, and an OverflowException is thrown if the count exceeds int.MaxValue. The following example returns the number of customers in London: int count = customers.Count(c => c.City == "London"); LongCount The LongCount operator counts the number of elements in a sequence.

public static long LongCount<TSource>( this IEnumerable<TSource> source); public static long LongCount<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); The LongCount operator enumerates the source sequence and counts the number of elements for which the predicate function returns true. If no predicate function is specified, the LongCount operator simply counts all elements. The count of elements is returned as a value of type long. For both Count operators, an ArgumentNullException is thrown if any argument is null, and an OverflowException is thrown if the count exceedslong.MaxValue. Sum The Sum operator computes the sum of a sequence of numeric values. public static Numeric Sum( this IEnumerable<Numeric> source); public static Numeric Sum<TSource>( this IEnumerable<TSource> source, Func<TSource, Numeric> selector); The Numeric type is one of int, int?, long, long?, float, float?, double, double?, decimal, or decimal?. The Sum operator enumerates the source sequence, invokes the selector function for each element, and computes the sum of the resulting values. If no selector function is specified, the sum of the elements themselves is computed. An ArgumentNullException is thrown if any argument is null. For the Numeric types int,int?, long, long?, decimal, and decimal?, if an intermediate result in computing the sum is too large to represent using the Numeric type, an OverflowException is thrown. For float, float?, double, and double?, a positive or negative infinity is returned if an intermediate result in computing the sum is too large to represent by using a double. The Sum operator returns zero for an empty sequence. Furthermore, the operator does not include null values in the result. (Null values can occur when theNumeric type is a nullable type.) The following example produces a sequence of customer names and order totals for a given year: int year = 2005; var namesAndTotals = customers. Select(c => new { c.Name, TotalOrders = c.Orders. Where(o => o.OrderDate.Year == year). Sum(o => o.Total) }); Min The Min operator finds the minimum of a sequence of numeric values. public static Numeric Min( this IEnumerable<Numeric> source); public static TSource Min<TSource>( this IEnumerable<TSource> source); public static Numeric Min<TSource>( this IEnumerable<TSource> source, Func<TSource, Numeric> selector); public static TResult Min<TSource, TResult>(

this IEnumerable<TSource> source, Func<TSource, TResult> selector); The Numeric type is one of int, int?, long, long?, float, float?, double, double?, decimal, or decimal?. The Min operator enumerates the source sequence, invokes the selector function for each element, and finds the minimum of the resulting values. If no selector function is specified, the minimum of the elements themselves is computed. The values are compared using their implementation of the IComparable<TSource>interface, or, if the values do not implement that interface, the non-generic IComparable interface. An ArgumentNullException is thrown if any argument is null. If the source type is a non-nullable value type and the source sequence is empty, an InvalidOperationException is thrown. If the source type is a reference type or a nullable value type and the source sequence is empty or contains only null values, null is returned. The Min implementations for the Numeric types are optimizations of the more general generic operators. The following example produces a sequence of name and lowest product price for each product category: var minPriceByCategory = products. GroupBy(p => p.Category). Select(g => new { Category = g.Key, MinPrice = g.Group.Min(p => p.UnitPrice) }); Max The Max operator finds the maximum of a sequence of numeric values. public static Numeric Max( this IEnumerable<Numeric> source); public static TSource Max<TSource>( this IEnumerable<TSource> source); public static Numeric Max<TSource>( this IEnumerable<TSource> source, Func<TSource, Numeric> selector); public static TResult Max<TSource, TResult>( this IEnumerable<TSource> source, Func<TSource, TResult> selector); The Numeric type is a type of int, int?, long, long?, float, float?, double, double?, decimal, or decimal?. The Max operator enumerates the source sequence, invokes the selector function for each element, and finds the maximum of the resulting values. If no selector function is specified, the maximum of the elements themselves is computed. The values are compared using their implementation of the IComparable<TSource>interface, or, if the values do not implement that interface, the non-generic IComparable interface. An ArgumentNullException is thrown if any argument is null. If the source type is a non-nullable value type and the source sequence is empty, an InvalidOperationException is thrown. If the source type is a reference type or a nullable value type and the source sequence is empty or contains only null values, null is returned. The Max implementations for the Numeric types are optimizations of the more general generic operators. The following example finds the total of the largest order in 2005: decimal largestOrder =

customers. SelectMany(c => c.Orders). Where(o => o.OrderDate.Year == 2005). Max(o => o.Total); Average The Average operator computes the average of a sequence of numeric values. public static Result Average( this IEnumerable<Numeric> source); public static Result Average<TSource>( this IEnumerable<TSource> source, Func<TSource, Numeric> selector); The Numeric type is a type of int, int?, long, long?, float, float?, double, double?, decimal, or decimal?. When the Numeric type is int or long, the Result type isdouble. When the Numeric type is int? or long?, the Result type is double?. Otherwise, the Numeric and Result types are the same. The Average operator enumerates the source sequence, invokes the selector function for each element, and computes the average of the resulting values. If no selector function is specified, the average of the elements themselves is computed. An ArgumentNullException is thrown if any argument is null. For the Numeric types int, int?, long, or long?, if an intermediate result in computing the sum of the elements is too large to represent in a long, anOverflowException is thrown. For the Numeric types decimal and decimal?, if an intermediate result in computing the sum of the elements is too large to represent in a decimal, an OverflowException is thrown. The Average operators for int?, long?, float?, double?, and decimal? return null if the source sequence is empty or contains only null values. The other Averageoperators throw an InvalidOperationException if the source sequence is empty. The following example computes the average order total for each customer: var averageOrderTotals = customers. Select(c => new { c.Name, AverageOrderTotal = c.Orders.Average(o => o.Total) }); Aggregate The Aggregate operator applies a function over a sequence. public static TSource Aggregate<TSource>( this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func); public static TAccumulate Aggregate<TSource, TAccumulate>( this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func); public static TResult Aggregate<TSource, TAccumulate, TResult>( this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector); The Aggregate operators with a seed value start by assigning the seed value to an internal accumulator. They then enumerate the source sequence, repeatedly computing the next accumulator value by invoking the specified function with the current accumulator value as the first argument and the current sequence element as the second argument. The operator without a

result selector returns the final accumulator value as the result. The operator with a result selector passes the final accumulator value to the supplied result selector and returns the resulting value. An ArgumentNullException is thrown if the source, func or resultSelectorargument is null. The Aggregate operator without a seed value uses the first element of the source sequence as the seed value, but otherwise functions as described above. If the source sequence is empty, the Aggregate operator without a seed value throws an InvalidOperationException. The following example produces a sequence of category name and longest product name for each product category: var longestNamesByCategory = products. GroupBy(p => p.Category). Select(g => new { Category = g.Key, LongestName = g.Group. Select(p => p.Name). Aggregate((s, t) => t.Length > s.Length ? t : s) });

S-ar putea să vă placă și