LINQ is a standard, unified query experience across different data sources, built directly into your .NET-supported programming language.. Whether a sequence of values is returned or a s
Trang 1Nielsen c33.tex V4 - 07/21/2009 2:06pm Page 772
Part V Data Connectivity
When tracking incremental changes, Sync Services uses net change tracking for peer-to-peer
synchroniza-tion This means that the latest version is synchronized and all changes to a given row are applied in
order at each peer
Peer-to-peer synchronization can be compared in many ways to a combination of offline data-set
technology and replication Sync Services provides a programming model like that of offline datasets
but with a feature set like that of replication As stated in the previous section, replication is a database
administrator function, but via Sync Services, developers can have the same synchronization support
through the many available synchronization classes, enabling developers to synchronize with other data
store types
Like the offline scenario, the choice between using peer-to-peer transaction replication versus using Sync
Services for peer-to-peer synchronization, it comes down to need Peer-to-peer transactional replication
is more of an administrator responsibility, but it does provide a highly available and scalable system and
requires almost no coding
Sync Services, however, is for developers It allows for synchronization of different transports or services,
and provides synchronization capabilities with data sources other than a database Sync Services is the
mechanism for moving beyond just replicating schema and data from one database to another
From an architecture standpoint, the peer-to-peer scenario has each peer containing its own application
code and Sync Services code to initiate and facilitate synchronization This functionality is provided via
the Sync Services peer-to-peer API During a typical synchronization, a pair of peers is synchronized
For example, given a scenario in which three peers need to be synchronized, synchronization could take
place like this: Peer1 and peer2 are synchronized, then peer1 and peer3, and then finally peer2 and
peer3 In each synchronization, one peer acts as the local peer, and one peer acts as the remote peer
However, this scenario might seem a bit redundant, as it is not necessary for each and every peer to be
synchronized In the earlier example, peer1 and peer2 could be synchronized, then peer2 and peer3
Peer1 and peer3 would be synchronized via peer2
As for the components used in a peer-to-peer synchronization, Figures 33-12 and 33-13 show which
components are used in a two-tier and n-tier architecture, respectively.
FIGURE 33-12
A two-tier architecture in peer-to-peer synchronization
DbSyncAdapter DbSyncAdapter
Computer
SyncOrchestrator
Trang 2Nielsen c33.tex V4 - 07/21/2009 2:06pm Page 773
Sync Framework 33
FIGURE 33-13
Ann-tier architecture in peer-to-peer synchronization with a proxy
DbSyncAdapter DbSyncAdapter
Local Computer Remote Computer
SyncOrchestrator Proxy Service
In a two-tier architecture, all the services exist on the local peer, as shown in Figure 33-12
In an n-tier architecture, a proxy and service are also introduced, and some of the services reside on the
remote computer, as shown in Figure 33-13
The n-tier architecture requires a service and a transport system which provides communication between
a proxy on the local computer and a service on the remote computer The difference between
peer-to-peer and client-server synchronization is that the proxy is not part of the Sync Framework API This
proxy must be written by the developer and must be derived from theKnowledgeSyncProvider
class
TheSyncOrchestratorin a peer-to-peer synchronization is responsible for the following:
■ Storing table information on the peer
■ Applying incremental changes to the peer database
■ Detecting conflict changes
■ Assisting applications in obtaining changes that occurred on the peer since the last
synchro-nization
By now it should be fairly clear that using Sync Services for ADO.NET 2.0 provides a very powerful yet
flexible synchronization mechanism There are many options to consider What makes Sync Services
great is simply how comprehensive it is for building offline and collaboration applications
Summary
This chapter provided a look at the Microsoft Sync Framework and Sync Services for ADO.NET 2.0
The chapter began by providing a brief and simple example demonstrating how easy it is to use this
great technology It then jumped feet first into first an overview, and then the architecture, of the Sync
Framework
That discussion was followed by an overview and architectural discussion about one of the Sync
Frame-work components, Sync Services, and why it should be considered when architecting offline solutions
Trang 3Nielsen c33.tex V4 - 07/21/2009 2:06pm Page 774
Trang 4Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 775
LINQ
IN THIS CHAPTER
Overview and history of LINQ Understanding LINQ
LINQ standard query operators Syntax options
LINQ to SQL LINQ to XML LINQ to Dataset LINQ to Entities
Let’s get right to the point I often see code like this:
string ConnectionString = @"Data Source=(local);
Initial Catalog = Adventureworks;UID=username;PWD=password";
using (SqlConnection conn = new
SqlConnection(ConnectionString))
{
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT LastName, FirstName,
MidleName FROM Person.Contact";
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// do something
}
}
Maybe you have also seen code like this or have even done it yourself, but at
some point in your career one of the two have happened Given the preceding
code, ask yourself two questions First, will it compile when run? Second, if so,
will it run successfully? Set aside for a minute the fact that there is noWHERE
clause and ignore the lack of encapsulation That is not the intent of this example
What is important are the two questions
First, yes, it will compile Second, when it runs it will fail It will fail because the
column ‘‘MidleName’’ should actually be ‘‘MiddleName.’’ The problem is that you
need to run the program in order to catch this Even worse, if your program does
error, where do you look? (That is, the developer was unaware that the column
name was misspelled.) Debugging an error such as this is time consuming and
unproductive Equally, the example is ‘‘unfriendly’’ on several levels First,
Trang 5Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 776
Part V Data Connectivity
two languages are being combined, in this case, C# and T-SQL The problem is that the T-SQL language
is not understood in the context of NET
Another nuisance is the fact that there is a different set of technologies for the different data sources
(SQL databases, XML, collections, in-memory objects, and so on) that developers work with on a daily
basis For example, you typically use ADO.NET to work with databases, but you might use XQuery,
XPath, or some of the XML classes built into the NET Framework to work with XML
Those are the two issues: Because queries against data are often written as strings embedded in code, the
result is no compile-time checking or IntelliSense support, as well as difficulty debugging; and multiple
technologies (different query languages) for different data sources (SQL, XML, etc.)
Wouldn’t it be nice if there were a way to solve both of these issues? Even better, wouldn’t it be nice if
there were a way to solve both of these issues with a single technology?
Luckily, there is an answer: Microsoft LINQ This chapter provides a brief history and overview of
LINQ, and then looks at the different LINQ providers, including examples that demonstrate how to
use them
LINQ Overview
Before looking at LINQ’s current incarnation, it would be wise to first look at its history Microsoft
LINQ has been in the works for well over five years LINQ (and other LINQ providers such as LINQ
to SQL) has roots that extend to previous projects, which have been growing and evolving for quite
some time
LINQ goes all the way back to a previous Microsoft project named C-Omega (or C) C-Omega, in its
fullness, really contained more than what shows up in LINQ, as it contained functionality that truly
experimented with using integrated queries (a mix of C# and other query languages such as SQL and
XQuery) C was initially released to the public as a preview in 2004, and it quickly caught the attention
of other Microsoft people (such as Anders Hejlsberg) who then took that same concept to C# and other
languages
Yet, as good as C-Omega was, LINQ now contains a lot of what C contained, plus many additional
fea-tures and functionality It could be said that LINQ ‘‘leapfrogged’’ over C Those familiar with Microsoft’s
ORM history know that LINQ to SQL is not Microsoft’s first endeavor at object-relational mapping The
roots of LINQ to SQL can actually be traced to something called ObjectSpaces dating back to 2001 In
simple terms, ObjectSpaces is a set of data access APIs that enable data to be treated as objects,
regard-less of the source of the data
This story has both a happy ending and a sad ending The sad ending is that ObjectSpaces was never
officially released, simply because ObjectSpaces depended on WinFS and when Microsoft made the
announcement that WinFS would not make it into the first release of Windows Vista, that was the end
of ObjectSpaces Happily, however, Microsoft learned a ton about ORM from ObjectSpaces and applied
that knowledge to LINQ to SQL, the result being a well thought-out and solid ORM product Is it the
ORM product to end all ORM products? No, but even for a first release, LINQ to SQL is surely nothing
to sneeze at
In the same category is a product called Nordic, developed by Paul Nielsen, which is a T-SQL-based
O/R DBMS fac¸ade It is a nice utility that uses code-gen to emulate an object-database It includes
Trang 6Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 777
polymorphism, inheritance, inheritable workflow states, and inheritable complex expressions Moreover,
according to Paul, it’s fast This nice tool can be found on CodePlex atwww.codeplex.com/Nordic
What Is LINQ?
LINQ stands for language-integrated query In essence, this means that developers have at their disposal
a query language integrated directly into their NET programming of choice (such as C# and Visual
Basic), giving them general-purpose query capabilities
LINQ is a standard, unified query experience across different data sources, built directly into your
.NET-supported programming language LINQ brings powerful query facilities to the NET Framework
lan-guages, such as C# and VB.NET Microsoft accomplished this by turning query set operations,
trans-forms, and constructs into high-level concepts (on the same level of classes and objects) within the NET
Framework LINQ makes a query a first-class construct within C# and Visual Basic
Moreover, LINQ addresses the very large mismatch between programming languages and data sources
such as databases, XML, and in-memory objects The entire goal of LINQ is to make the interaction
between objects and data sources easier and simpler, enabling developers to interact with the different
data sources (such as SQL and XML), because there is a disconnect between the data sources and the
programming languages that communicate with (that is, work with) each of them
As stated earlier, LINQ is a ‘‘unified’’ query experience This means that it unifies data access regardless
of the source of data Simply stated, LINQ bridges the gap between the world of data and the world of
programming
Prior to LINQ, developers had to learn different technologies to query different data sources No more!
LINQ gives developers a new way of querying different types of data using strongly typed queries
com-mon across many different data sources The result is improved developer productivity along with
LINQ-specific IntelliSense in the Visual Studio IDE and compile-time error checking!
That’s right Because developers are now working with data in an object-oriented fashion, they are also
working in a strongly typed environment The benefits of this include compile-time error checking, not
runtime error checking In addition, developers can now write queries using Visual Studio’s IntelliSense,
driving the experience toward a more declarative programming model
Because LINQ makes a query a first-class construct within the programmer’s development language,
developers can now write and execute queries against strongly typed objects using keywords, or
operators These keywords, called standard query operators, are discussed in the next section.
Who should use LINQ? The real question is who shouldn’t use LINQ? LINQ is targeted toward
appli-cation developers who want a new way to query data using strongly typed queries and strongly typed
results It is for developers seeking commonality across a number of different data sources, including but
not limited to relational databases It is for developers who want improved productivity — and who like
using really cool technology
Standard Query Operators
Standard query operators are essentially methods that form the LINQ pattern They provide the query
capabilities, including filtering, projection, sorting, and more A large portion of these methods that
make up the standard query operators operate on sequences, objects that have implemented the
IEnumerable<T>orIQueryable<T>interface These two interfaces are what provide the querying
and iteration for queries over a non-generic collection
Trang 7Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 778
Part V Data Connectivity
There are two sets of standard query operators that implement the two interfaces mentioned above
The key to remember when working with the standard query operators is that regardless of the
set, each method of the standard query operators is a static member of theEnumerableand
Queryableclasses, meaning they can be called using either static method syntax or instance method
syntax
The standard query operators also vary in their execution timing This timing depends on the results
of the query Whether a sequence of values is returned or a singleton value is returned determines
when the query is executed Methods are executed immediately if they return a singleton value;
otherwise, the query execution is deferred and an enumerable object is returned if the method returns a
sequence
Table 34-1 lists the 53 standard query operators, grouped according to their functionality
Query expression syntax
To understand the flow of LINQ query syntax, compare it to standard T-SQL syntax If you have written
any T-SQL, you know the basic T-SQL query syntax and how it is written For instance, a simple query
looks like the following:
SELECT FirstName, LastName FROM Person.Contact
TABLE 34-1
Standard Query Operators Functionality Standard Query Operator Description
Sorting OrderBy Sorts values in ascending order
OrderByDescending Sorts values in descending order ThenBy Applies a secondary sort in ascending order ThenByDescending Applies a secondary sort in descending order Reverse Sorts the elements of a collection in reverse order Set Distinct Removes duplicate values from a collection
Except Returns the differences between two sets (elements in
one collection that do not exist in a second collection) Intersect Returns the matches between two sets (elements that
appear in two separate collections) Union Returns the union of two sets (unique elements that
appear in either of two collections)
continued
Trang 8Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 779
TABLE 34-1 (continued )
Functionality Standard Query Operator Description
Filtering OfType Selects values from a sequence based on their ability to
be cast to a specified type Where Selects values from a sequence based on a predicate
function Quantifier All Determines whether all the elements in a sequence meet
a condition Any Determines whether any of the elements in a sequence
meet a condition Contains Determines whether a sequence contains a specified
element Projection Select Projects values based on a transform function
SelectMany Projects sequences of values based on a transform
function and then combines them into a single sequence Partitioning Skip Skips elements up to a specified position in a sequence
SkipWhile Skips elements based on a predicate function until an
element does not satisfy the condition Take Takes elements up to a specified position in a sequence
TakeWhile Takes elements based on a predicate function until an
element does not satisfy the condition Join Join Joins two sequences based on key selector functions
GroupJoin Joins two sequences based on key selector, grouping the
matches for each element Grouping GroupBy Groups elements that share a common attribute
ToLookup Inserts elements into a Lookup(TKey, TElement)
Generation DefaultIfEmpty Replaces an empty collection with a default singleton
collection Empty Returns an empty collection
Range Generates a collection that contains a sequence of
numbers Repeat Generates a collection that contains one repeated value
Equality SequenceEqual Determines whether two sequences are equal by
comparing elements in a pair-wise manner
continued
Trang 9Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 780
Part V Data Connectivity
TABLE 34-1 (continued )
Functionality Standard Query Operator Description
Element ElementAt Returns the element at a specified index in a collection
ElementAtOrDefault Returns the element at the specified index in a
collection, or the first element that satisfies a condition First Returns the first element of a collection, or the first
element that satisfies a condition FirstOrDefault Returns the first element of a collection, or the first
element that satisfies a condition A default value is returned if the specified element does not exist
Last Returns the last element of a collection or the last
element that satisfies a condition LastOrDefault Returns the last element of a collection or the last
element that satisfies a condition A default value is returned if the specified element does not exist in the collection
Single Returns the only element of a collection or the only
element that satisfies a condition SingleOrDefault Returns the only element of a collection or the only
element that satisfies a condition A default value is returned if the specified element does not exist in the collection
Conversion AsEnumerable Returns the input types as IEnumerable(T)
AsQueryable Converts a generic IEnumerable to a generic
IQueryable Cast Casts the elements of a collection to a specified type OfType Filters values based on their ability to be cast to a
specified type ToArray Converts a collection to an array Forces query
execution
ToDictionary Puts elements into a Dictionary(TKey, TValue)
Forces query execution
ToList Converts a collection to a List(T) Forces query
execution
ToLookup Puts elements into a Lookup(TKey, TValue)as a
one-to-many dictionary Forces query execution
continued
Trang 10Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 781
TABLE 34-1 (continued )
Functionality Standard Query Operator Description
Concatenation Concat Concatenates two sequences into a single sequence
Aggregation Aggregate Performs a custom aggregation operation on the values of
a collection Average Calculates the average value of a collection of values Count Counts the elements in a collection; optionally, only
those elements that satisfy a predicate expression LongCount Counts the elements in a large collection; optionally,
only those elements that satisfy a predicate expression Max Determines the maximum value in a collection Min Determines the minimum value in a collection Sum Calculates the sum of the values in a collection
This example queries thePerson.Contacttable in the AdventureWorks database and returns the
FirstNameandLastNamecolumns for each row in the table Because that’s so simple, the following
example adds a secondary table, and then applies a filter and a sort:
SELECT E.EmployeeID,C.FirstName, C.LastName
FROM Person.Contact AS C
INNER JOIN HoumanResources.Employee AS E ON C.ContactID = E.ContactID
WHERE E.EmployeeID < 100
ORDER BY C.LastName
This is the syntax with which all T-SQL developers are familiar At the very minimum, the query begins
with aSELECTclause, which specifies the columns you want to be returned by the query, followed
by aFROMclause, which lists the tables and/or views containing the columns identified in theSELECT
clause
The query could include one or more joins such as anINNER JOINorOUTER JOIN, followed by some
filtering using theWHEREclause and possibly aGROUP BYorHAVINGclause, and quite possibly some
ordering using theORDER BYclause
How many developers have really stopped to think about how SQL Server processes these queries? Does
it execute the query from top to bottom, starting with the SELECTclause and working its way down?
One might assume that, but that is not how a query is processed in SQL Server at all SQL Server
logi-cally processes a query in the order indicated here by the number in parentheses:
(8) SELECT
(9) TOP
(1) FROM
(3) JOIN
(2) ON