Chapter 17. LINQ Everywhere

This chapter points to the future, to the ways in which LINQ will be used in the coming years. The primary goal is to give you an overview of several alternative LINQ providers not covered in the previous chapters. You’ve read about LINQ to Objects, LINQ to SQL, and LINQ to XML. These technologies shipped with Visual Studio 2008 and C# 3.0, but they are only a portion of the larger, still-emerging LINQ story.

The providers covered in this chapter are examples of what LINQ will become in future years. LINQ is not just about the existing providers we have studied in this book. It is about the potential to create providers for many other data sources.

Many of the most important tasks performed on computers involve manipulating data. In fact, it could be argued that computers are really for working with a disparate set of data sources. LINQ is important because it provides a concise, unified, integrated way to work with a wide variety of data sources.

Other Flavors of LINQ

This chapter introduces several variants of the LINQ technology so that you can get a feel for how LINQ is used throughout the industry. LINQ is an extendable technology, and over the years, it will be used in many different ways, for many different purposes. The main goal of this chapter is to give you a sense of the variety of possible LINQ services, in part so that you can be aware of their existence, and in part so that you can begin to imagine the uses to which LINQ can and will be put.

This book has covered LINQ to Objects, LINQ to SQL, and LINQ to XML in considerable depth. The topics covered in this chapter, however, are introduced only briefly. Nearly all of them are currently still under development, and several of them are potentially very large subjects. Nevertheless, I hope that this brief introduction to these technologies will give you a sense of their potential.

Finally, I should point out that I will mention an open-source product called LINQExtender. This tool is designed to help you build your own LINQ extensions. One of the technologies discussed in this chapter, LINQ to Flickr, is built on top of LINQExtender. Even though I will not discuss LINQExtender, that project is a place to start if you want to explore that technology.

Parallel LINQ

The code shown in this section uses a prerelease version of PLINQ called the Microsoft Parallel Extensions to .NET Framework 3.5. When PLINQ finally ships, it will run only on .NET 4.0 or later. The version I’m using that runs on top of 3.5 is for evaluation purposes only. There will never be a shipping version that runs on .NET 3.5.

This LINQ provider is being created at Microsoft by the Parallel Computing team; it is not the work of the C# team that created LINQ to Objects and LINQ to SQL. Here is the web site for the Parallel Computing team:

http://msdn.microsoft.com/en-us/concurrency/

Currently, these extensions are available only in prerelease form. You could download them either as Visual Studio 2008 compatible extensions to .NET 3.5, or as part of the prerelease version of Visual Studio 2010. Because the download sites might change over the coming months, I suggest that you find these resources by going to the Parallel Computing site or the Visual Studio site:

http://msdn.microsoft.com/en-us/vs2008

Parallel LINQ, or PLINQ, is only a small part of the Parallel Extensions to the .NET Framework. It is, however, an important part. Because it is a simple and natural extension of the material covered in this book, I think you will find it easy to use.

Consider this code fragment:

var list = Enumerable.Range(1, 10000);

var q = from x in list.AsParallel()
        where x < 3300
        select x;

foreach (var x in q)
{
    Console.WriteLine(x);
}

These lines look nearly identical to the code you have seen so often in this book. The only significant difference is the call to AsParallel at the end of the second line. Although we have often used type inference to hide the return type of a LINQ query, I’ll pause and take a second look at this instance. Rather than returning IEnumerable<T>, this version of PLINQ returns IParallelEnumerable<int>:

IParallelEnumerable<int> q = from x in list.AsParallel() etc...

In the near future, PLINQ queries of this type will probably return ParallelQuery<int>. Because this product is still evolving, it might be simplest to use var, at least during the prerelease phase, and let the compiler choose the type. That way, you can save typing and avoid problems with anonymous types, and you need not concern yourself with changes in the API as the product develops. As was made clear earlier in the book, it is almost always appropriate to use var to designate the return type of a LINQ query, and there are generally only special circumstances when you would do otherwise.

Here are the results of this first PLINQ query:

2
1
3
4

6
512
5
7
513
8
12
514
9
13
515
10
14
516
11
15
517
16
72
518
17

The numbers shown here are in a relatively random order because they are being returned from different threads. It is important to remember that the sequence of values returned by LINQ is not always guaranteed to be presented in a particular order. If order is important in your code, you can add a call to AsOrdered to the query after the call to AsParallel. Alternatively, you could insert a GroupBy clause to establish the desired ordering. Otherwise, developers should assume that the ordering from a PLINQ query will be random.

Query Data with Parallel LINQ

Now that you understand the basics of Parallel LINQ, let’s move on to look at a more interesting example. Improved performance is the main reason to write code that can run in parallel. The program shown in this section uses a timer to demonstrate how PLINQ can improve performance in a program.

Performance improvements become more evident when our code has access to more processors. The code I show here runs faster on a two-processor machine, but it really starts to come into its own on a four-processor machine. Moving up to even more processors yields more powerful results. For instance, the following results show an improvement of 1.44 times when using two processors and almost two times when using four processors:

2 Processors = 1.44 × improvement:
Linear: 00:00:13.15
Parallels: 00:00:09.10

4 Processors = 1.96 × improvement:
Linear: 00:00:15.00
Parallel: 00:00:07.68

These tests were run against prerelease software, so these numbers are almost certain to change before release, and, of course, different machines yield different results. Furthermore, the degree of improvement you will see is likely to change depending on the type of algorithm you run, the number of cores on your machine, the machine’s architecture, how many caches there are, how they’re laid out, and so on. Although it is rare, some queries show superlinear performance enhancements. In other words, there is a greater than four-fold speedup on a four-core box. An improvement of two times, such as the one shown, or even a three-time improvement, is common.

The following sample program is called FakeWeatherData, and it is available with the other programs that accompany this book. It features a simple LINQ to XML query run against a file with 10,000 records in it. The data I’m querying is not real. It consists of random dates and temperatures generated by a simple algorithm included in the FakeWeatherData program.

The XML file is structured like this:

<?xml version="1.0" encoding="utf-8" ?>
<Samples>
  <Sample>
    <Year>1973</Year>
    <Month>May</Month>
    <Day>15</Day>
    <Temperature>10</Temperature>
  </Sample>
  <Sample>
    <Year>1970</Year>
    <Month>Feb</Month>
    <Day>10</Day>
    <Temperature>14</Temperature>

  </Sample>
  ... 9,998 records omitted here
</Samples>

The program also uses a simple C# class to encapsulate the data from the XML file:

class WeatherData
{
    public string Year { getset; }
    public string Month { getset; }
    public string Day { getset; }
    public string Temperature { getset; }
}

The parallel version of the query in the program looks like this:

var list = (from x in doc.Root.Elements("Sample").AsParallel()
            where x.Element("Year").Value == "1973" &&
               x.Element("Month").Value == "Apr" &&
               x.Element("Day").Value == "15"
            select new WeatherData
            {
                Day = x.Element("Day").Value,
                Month = x.Element("Month").Value,
                Temperature = x.Element("Temperature").Value,
                Year = x.Element("Year").Value
            }).ToList();

Accompanying this code is a similar LINQ query that does not use PLINQ:

var list = (from x in doc.Root.Elements("Sample")
            where x.Element("Year").Value == "1973" &&
               x.Element("Month").Value == "Apr" &&
               x.Element("Day").Value == "15"
            select new WeatherData
            {
                Day = x.Element("Day").Value,
                Month = x.Element("Month").Value,
                Temperature = x.Element("Temperature").Value,
                Year = x.Element("Year").Value
            }).ToList();

The program queries the data in the XML file first using the parallel code and then using standard LINQ. By comparing the time it takes each block of code to execute, you can get a sense of the relative improvement available through PLINQ. I’ll show you how to make such comparisons in a moment. I will also discuss some tools that will become available to help profile code of this type.

You can see that the PLINQ query contains a call to AsParallel, but the other query does not. Other than that, the two queries are identical. The fact that the two queries look so much alike points to a primary strength of PLINQ: Very little specialized knowledge is necessary to begin using it. This does not mean that the subject is utterly trivial—only that the barrier to entry is low. This is not the case with most concurrent programming models.

LINQ queries are designed to be read-only, working with immutable data. This is a good model for parallelism, because it makes it unlikely that data will mutate, thereby setting up the potential for a race condition. You should note, however, that PLINQ does nothing to prevent this from happening; it is simply that LINQ is designed to make it unlikely.

Note also that the declarative LINQ programming style ensures that developers specify what they want done, rather than how it should be done. This leaves PLINQ free to ensure that concurrent LINQ queries run in the safest manner possible. If LINQ had been defined more strictly, such that it had to process each element in a certain order, the PLINQ team would have had a much more difficult task.

The code in both these queries pulls out only the records from the XML file that have their date set to April 15, 1973. Because of deferred execution, the query would not do anything if I did not call ToList(). As a result, I added that call and converted the result into a List<WeatherData>. Although hardly earthshaking in importance, these calls ensure that the code actually does something, and thus give PLINQ scope to take advantage of the multiple processors on your system.

Simple timers are created to measure the difference between the standard LINQ query and the PLINQ query:

private static void RunTest()
{
    XDocument doc = XDocument.Load("XMLFile1.xml");

    Stopwatch sw = new Stopwatch();

    sw.Start();
    LinqOrdinarie(doc); // Run the regular LINQ query


    sw.Stop();
    ShowElapsedTime("Linear", sw.Elapsed);

    sw.Reset();

    sw.Start();
    ParallelLinq(doc); // Run the PLINQ query
    sw.Stop();
    ShowElapsedTime("Parallels", sw.Elapsed);
}

// Format and display the TimeSpan value.
private static TimeSpan ShowElapsedTime(string caption, TimeSpan ts)
{
    string elapsedTime = String.Format("{0}: {1:00}:{2:00}:{3:00}.{4:00}",
        caption, ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);
    Console.WriteLine(elapsedTime, "RunTime");
    return ts;
}

At least with the prerelease version of PLINQ that I’ve played with, I’ve found it very useful to set up timers to confirm that PLINQ actually can speed up an operation. My record at guessing which code will benefit from running in parallel is not good, so I find that confirming the code’s effectiveness by explicitly measuring it is worthwhile. You can either use the simple StopWatch class from the System.Diagnostics namespace, as shown here, or you can use a profiler. Note that a thread-aware profiler might ship with some versions of Visual Studio 2010.

I’ve found that the advantages of concurrent LINQ become more obvious the longer the operation I’m timing lasts. As a result, I’ve placed the query inside a loop and added a variable to the program called NUM_REPS. By setting NUM_REPS to a large number, such as 500, you can clearly see the benefits that can be accrued when you run LINQ queries in parallel on multiple processors. Note that the first time PLINQ is used, its assembly needs to be loaded, the relevant types need to be JIT compiled, new threads need to be spun up, and so on. As a result, many developers see improved performance after they get past the initial warm-up time.

Although it is very easy to get started with PLINQ, you still need to consider complexities that are inherent in the subject. For instance, PLINQ sometimes develops a different partitioning scheme for your data, depending on whether you are working with an enumerable or an array. To learn more about this subject, see the following post from the Parallel Programming team:

http://blogs.msdn.com/pfxteam/archive/2007/12/02/6558579.aspx

The simple PLINQ examples shown in this section should help you get started with this powerful and interesting technology. Parallel LINQ is still in its infancy, but already it provides a way to greatly simplify tasks that normally are not easy to perform.

LINQ to Flicker

LINQ to Flickr allows developers to write queries against the Flickr repository of images hosted by Yahoo!. It also allows you to upload and delete photos from your stream and to create and remove comments. I’ve elected to show LINQ to Flickr in this chapter because it is reasonably well written and runs against a data resource, Flickr, that nearly all developers can access.

Flickr is a repository for photographs. It is a public site that you can use without charge. It is located at http://www.flickr.com/.

You can create your own free Flickr account and upload pictures to it that can be shared with the public. If you have an existing Yahoo! account, you are already automatically a member of the Flickr community.

Flickr supports an API that allows you to write queries against photos that are hosted on the site. This API forms the foundation on which LINQ to Flickr is built. The documentation for the API is found here:

http://www.flickr.com/services/api/

You can apply for a free API key that allows you to log into Flickr and call the API:

http://www.flickr.com/services/api/keys/

LINQ to Flickr is a LINQ provider that wraps the API and allows you to write traditional LINQ queries against the data in the Flickr repository. From a developer’s point of view, LINQ to Flickr is simply another flavor of LINQ, such as LINQ to SQL, LINQ to Objects, or LINQ to XML. Behind the scenes it uses the Flickr API, but that fact is not at all obvious. Nor do you need to understand the API to use LINQ to Flickr. You only need to know LINQ.

Here is the URL for the web site from which you can download LINQ to Flickr:

http://www.codeplex.com/LINQFlickr

LINQ to Flickr (also known as Athena) is built on top of a tool called LINQ-Extender. The DLL that encapsulates LINQExtender comes with LINQ to Flickr, but if you want your own copy of the source for LINQExtender, you can download it here:

http://www.codeplex.com/LinqExtender


Other Provider Toolkits

LINQExtender is not the only tool of its kind. See, for instance, the LINQ IQueryable Toolkit (http://www.codeplex.com/IQToolkit). All this technology is quite new. In this chapter I’m simply providing links to these resources; I’m not yet ready to make a judgment as to which tool is best.


The author of LINQ to Flickr, Mehfuz Hossain, has also written an application that demonstrates what can be done with his code. This reference application is called FlickrXplorer, and it can be downloaded here:

http://www.codeplex.com/FlickrXplorer

FlickrXplorer is a web application. You can compile and run it yourself, or you can access a copy of it here:

http://www.flickrmvc.net/

To compile FlickrXplorer, you need a copy of a Microsoft library called MVC installed on your system. You can download MVC here:

http://www.asp.net/mvc/

MVC is an interesting and powerful tool in its own right, but I will not discuss it here. You can use LINQ and MVC in the same application, but there is no direct connection between the two technologies.

To create a LINQ to Flickr application, first create a simple console application. Add an application configuration file to the project by selecting Project, Add New Item in Visual Studio. Select Application Configuration File, and click the Add button. Insert the following contents into the configuration file, and insert your personal Flickr API keys where indicated:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="flickr"
        type="Linq.Flickr.Configuration.FlickrSettings, Linq.Flickr"/>
  </configSections>

  <flickr apiKey="INSERT YOUR API KEY"
    secretKey="INSERT YOUR SECRET KEY"
    cacheDirectory="cache/>
</configuration>

In the References section of Visual Studio Solution Explorer, add these two DLLs, which are part of the LINQ to Flicker download from CodePlex:

Linq.Flickr.dll

LinqExtender.dll

Note that LinqExtender depends on the System.Core namespace.

When you are done, Solution Explorer should show that you have added the libraries to the References section, as shown in Figure 17.1. In the Solution Explorer, you can also locate the App.config file with your API keys.

Figure 17.1. Linq.Flickr.dll and LinqExtender.dll are visible in the References section of Solution Explorer, along with the application configuration file.

image

Listing 17.1 shows the code for your program.

Listing 17.1. The Code for a Simple LINQ to Flickr Application

using System;
using System.Linq;
using Linq.Flickr;

namespace LinqToFlickrTest
{
    class Program
    {
        static void Main(string[] args)
        {
            FlickrContext context = new FlickrContext();

            var query = from photo in context.Photos
                        where photo.SearchText == "IMG" &&
                           photo.ViewMode == ViewMode.Owner
                        select photo;


            Console.WriteLine("Pictures found {0}", query.Count());

            foreach (var item in query)
            {

                Console.WriteLine("{0} {1}""FileName", item.FileName);
                Console.WriteLine("{0} {1}""Title", item.Title);
                Console.WriteLine("{0} {1}""WebUrl", item.WebUrl);
                Console.WriteLine("{0} {1}""Url", item.Url);
            }

        }
    }
}

Note that the search term I’ve chosen may not work for the pictures in your Flickr repository. I’ve used the string "IMG" here, but you might want to choose some other string used in the title or description of your pictures.

Although it is not absolutely necessary, you will find that things go more smoothly if you are logged into Flickr before running the program. Even though this is a console application, your browser opens the first time you run this application, and you are taken to the Flickr site. It reports that you have “successfully authorized the application.” If you are not currently logged in, you are asked to log in before you see this message. Here is the exact text of the message I received from the Flickr site:

You have successfully authorized the application.
You can go ahead and close this window now.
If you ever want to revoke authorization, you can do that in your
account.

At this stage you should be all set to retrieve results from the site. For instance, the code just shown returns the following data in my case, although it is likely that you will retrieve different information:

Pictures found 2

FileName:  3bc8f41b-d921-4ab9-b170-15b544e8e41d
Title:  IMG_1852
WebUrl: http://www.flickr.com/photos/53173747@N00/3085317496/
Url: http://farm4.static.flickr.com/3210/3085317496_536df49d80_s.jpg?v=0

FileName: 07fb7451-7395-4584-8f87-5eca6062058e
Title: IMG_1764
WebUrl: http://www.flickr.com/photos/53173747@N00/3084242106/
Url: http://farm4.static.flickr.com/3189/3084242106_938c17c616_s.jpg?v=0

That is all I’ll say about LINQ to Flickr. Like nearly all the code shown in this chapter, LINQ to Flickr is still under development and is likely to change before it is finished. Hopefully I’ve given you enough information that you can get up and running using this relatively sophisticated, powerful, easy-to-use tool. Mehfuz has done us all a favor by working so hard to create this well-designed program. I hope you have fun working with it.

LINQ to SharePoint

LINQ to SharePoint is a powerful tool created primarily by Bart De Smet, a talented Microsoft employee who works on the WPF team. It is designed to allow you to run LINQ queries against the data stored in the lists found on a SharePoint site.

Like LINQ to Flickr, LINQ to SharePoint is hosted on CodePlex:

http://www.codeplex.com/LINQtoSharePoint

Go to the Releases tab on CodePlex, and download the MSI. There is also a zip file containing the source for the project, but you need the source only if you want to see how the project is constructed. You don’t need the source just to use LINQ to SharePoint.

Microsoft does not support the LINQ to SharePoint download from the CodePlex site, but Bart has done a great job with this technology. Even the early version I worked with for this chapter is quite sophisticated and easy to use.

Users of LINQ to SharePoint need access to a SharePoint site they can query. The official name and current version of SharePoint is Windows SharePoint Services 3.0, SP1. Don’t be confused. If you saw a product called Visual Studio Services, you would rightfully think it was not Visual Studio itself. And if you saw a product called Windows Vista Services, again, you would be right to think it was not Vista itself. But in this case, Windows SharePoint Services is SharePoint. (Providing a rational explanation for this naming scheme is beyond the scope of this book!)

There are at least three ways to get access to a SharePoint site:

• You might have access to a SharePoint site through your workplace. If you can sign into a SharePoint site, you will probably have the rights to query it with LINQ to SharePoint.

• You can download and install a free version of SharePoint Services 3.0 if you have control of a machine that runs Windows Server 2003 or Windows Server 2008.

• There is also a one-month trial version of SharePoint called Microsoft Office SharePoint Server 2007 VHD. This and many other useful Virtual PC files are available at http://www.microsoft.com/vhd.

No real setup is involved with the first and third options. Instead, I will focus on option 2, which I believe is the best way to get to know and understand SharePoint, and the best way to experiment with the possibilities inherent in LINQ to SharePoint.

As you have read, SharePoint is a free download, but you must have Windows Server 2003 or 2008 to run it. While writing this book, I used a copy of Windows Server 2008, the 64-bit version. To install SharePoint on that OS, I first used W2K8 Server Manager to add the Web Server (IIS) Role. Then I downloaded the 64-bit version of Windows SharePoint Services 3.0, SP1. I ran the install and chose the Basic setup. This is pretty much a forehead install, which means that it requires very little effort. When I was done, I had a copy of SharePoint up and running on my system, as shown in Figure 17.2.

Figure 17.2. A nearly pristine new SharePoint site with the default configuration.

image

After installing SharePoint, I clicked the Add new announcement button, shown in Figure 17.2. I typed in a new announcement, as shown in Figure 17.3, and then clicked OK.

Figure 17.3. Adding a new announcement to a SharePoint site.

image

Now that you have a copy of SharePoint set up, you can go to the CodePlex link listed earlier in this section and download LINQ to SharePoint. The install for this product is very simple and requires no explanation.


Registering the Assemblies

After I installed LINQ to SharePoint and tried to use the LINQ to SharePoint Wizard inside the IDE, I received an error stating Could not load file or assembly BdsSoft.Sharepoint.Tools.EntityGenerator.dll. This error occurs on the 0.2.4 release of LINQ to SharePoint. It is the result of a failed install into the GAC of the assemblies that are needed to run LINQ to SharePoint. If you encounter this problem, you can fix it as follows:

1. Open a command prompt with Administrator privileges.

2. Locate the BdsSoft assemblies, which are probably in a directory like this one:

%ProgramFiles%BdsSoft LINQ to SharePoint

3. Create a text file called GacFiles.txt containing a list of all the DLLs in the BdsSoft directory:

BdsSoft.SharePoint.Linq.dll

BdsSoft.SharePoint.Linq.ObjectModelProvider.dll

BdsSoft.SharePoint.Linq.Tools.DebuggerVisualizer.dll

BdsSoft.SharePoint.Linq.Tools.EntityGenerator.dll

BdsSoft.SharePoint.Linq.Tools.Installer.dll

BdsSoft.SharePoint.Linq.Tools.Spml.dll

4. Make sure that the GacUtil.exe file is in your path. It is probably located here:

C:Program FilesMicrosoft SDKsWindowsv6.0ABin

Alternatively, open the Visual Studio command prompt from the Windows Start menu.

5. Issue this command:

Gacutil.exe /il GacFiles.txt


After completing the install of LINQ to SharePoint, you are ready to run a sample program. Create a standard console application by selecting File, New Project, Console Application from Visual Studio. Choose Project, Add New Item. Select LINQ to SharePoint File, as shown in Figure 17.4.

Figure 17.4. Selecting the LINQ to SharePoint template from the Add New Item dialog.

image

After you select the SharePoint template, Visual Studio takes you to the LINQ to SharePoint Entity Wizard, as shown in Figure 17.5. Currently, an options dialog available from the first screen of the wizard allows you to decide how to handle the plural forms of names from a SharePoint database. There is no need to use that dialog when creating this sample.

Figure 17.5. The first screen of the LINQ to SharePoint Entity Wizard.

image

The second page of the LINQ to SharePoint Wizard lets you enter the name of the SharePoint site to which you want to connect. Enter your URL, as shown in Figure 17.6, and click the Test connection button. If the connection succeeds, the Next button becomes active, allowing you to move to the next page of the wizard.

 

Figure 17.6. Connecting to a SharePoint site using the SharePoint Entity Wizard.

image

The URL shown in Figure 17.6 is the URL of the name of the server on which I developed the applications for this section. The URL will likely differ on your machine; it may take a more standard form, such as http://www.mysite.com.

There are two ways to select the credentials for your site. You can sign in with your default network credentials or sign in with custom credentials. The choice you make depends on how your network and SharePoint instance are configured. If you have questions, find the people who run your SharePoint site, and ask them for details.

The next page in the wizard allows you to choose the lists from the SharePoint site that you want to query in your program, as shown in Figure 17.7. This is roughly the equivalent of choosing the tables from the database that you want to query when using the Object Relational Mapper in a LINQ to SQL application. The default is not to have the Object Model option turned on, because that works only for querying a local machine.

Figure 17.7. Choosing the lists from the SharePoint site that you want to query from your program.

image

The final screen in the wizard allows you to review the choices you made while stepping through the wizard, as shown in Figure 17.8. You can see that we have chosen to create an entity for the list of Announcements on the SharePoint site found on the machine called Charlie007. Our DataContext that we can use to gain access to the lists on the site is called DataClasses1SharePointDataContext.

Figure 17.8. We are connected to machine charlie007 using the default network credentials, and we have generated an entity for the list of announcements.

image

If everything looks in order, go ahead and click Finish in the wizard. At this point, code similar to what is produced by the LINQ to SQL Object Relational Designer is added to your project. A new node with a name like MySharePointSite.spml is added to Solution Explorer, and inside that node is a file with a name like MySharePointSite.designer.cs. This file contains a SharePointDataContext that is roughly equivalent to the DataContext found in a LINQ to SQL project. It contains one class for each entity you opted to import from the SharePoint site. Again, it is easy to draw parallels between the code in this file and the code generated by the Object Relational Designer or SqlMetal in a LINQ to SQL project. Note that LINQ to SharePoint ships with a program called SpMetal, which is roughly equivalent to SqlMetal.

When you are done, Solution Explorer looks something like Figure 17.9. Note the presence of the BdsSoft assemblies in the References section. An ObjectModelProvider entry will be present if you selected that option.

Figure 17.9. Solution Explorer after you have imported several SharePoint lists into your project with the LINQ to SharePoint wizard.

image

After you finish running the wizard, you can begin writing queries against the SharePoint data found on your site. Here, for instance, is a simple query against the common Announcements section that is part of many SharePoint sites:

MySharepointSiteSharePointDataContext db =
   new MySharepointSiteSharePointDataContext();

var query = from c in db.Announcements
            select c;

foreach (var item in query)
{
    Console.WriteLine(item.Title);
}

Note that we begin by creating a SharePointDataContext, just as we begin by creating a DataContext when building a LINQ to SQL application. You can then issue a query using the same syntax you would use in a standard LINQ to SQL or LINQ to Objects application.

The simple C# team community site that I’m querying returns the following data, which of course will differ from the data on your site:

This is my first announcement on my SharePoint site
Get Started with Windows SharePoint Services!

After you get started, it is easy to see the next steps. You can begin adding a where clause, for instance:

var query = from c in db.Announcements
            where c.Title.StartsWith("T")
            select c;

This query would retrieve the first, but not the second, of the two announcements returned by the first version of this query. You can experiment with the other LINQ operators, finding which ones work and which ones might not have been implemented yet. It is unlikely that LINQ to SharePoint will ever implement all 49 operators covered in Chapter 6, “Query Operators.” Nevertheless, this tool is still under development, and it will grow in depth over time.

That is really all you need to know to get started using LINQ to SharePoint. As you can perhaps tell, this is quite a sophisticated tool that is well designed and easy to use. Currently LINQ to SharePoint does not support all the query operators available in LINQ to SQL. I should add that the author of LINQ to SharePoint has no plans to implement all the operators, but he is busy adding new ones, such as the join operator.

Overall, LINQ to SharePoint is an excellent example of what can be done to extend LINQ. It is also a very useful tool that should be valuable to many developers. If you use SharePoint regularly, you will find this tool an excellent resource.

Working with Processes

I want to close this chapter with a simple example that I hope will serve as a cautionary note for LINQ developers. When I first started working with LINQ, I was not fully aware of the power of LINQ to Objects. Unfortunately, I have seen developers do a great deal of work to create a LINQ provider for a technology that LINQ to Objects already fully supports. Remember that any data source that produces an IEnumerable<T> or IEnumerable can be queried by LINQ to Objects without any extra work on your part. If you want to use LINQ with a particular technology, check to see if it already supports LINQ to Objects or if it would be possible to quickly convert your data source into an array of some kind that fully supports LINQ queries. If you can do so without paying too great a price in terms of performance, don’t worry about the need to create your own provider.

To illustrate the point, I ask you to recall material covered in earlier chapters on using LINQ with the C# Reflection API. The code shown in those samples is commonly called LINQ to Reflection, but it’s really just LINQ to Objects run against the collections produced by the Reflection API. The code may appear to magically pull data from the Reflection API, but, in fact, it just uses LINQ’s capability to work with methods that return IEnumerable or IEnumerable<T>.

Listing 17.2 shows an example of a query that you might be tempted to think is part of something called LINQ to Diagnostics. In fact, this is just another example of the power inherent in LINQ to Objects. Listing 17.3 shows the output.

Listing 17.2 contains a query that retrieves and filters the processes running on your machine. To write such code, you need do no special work. Instead, you can write a LINQ to Objects query directly against a class found in the System.Diagnostics namespace.

Listing 17.2. By Using the System.Diagnostics Namespace, You Can Write Queries Against the Processes Currently Running on Your System

static void Main(string[] args)
{
    var query = from p in Process.GetProcesses()
                orderby p.VirtualMemorySize64 descending
                select p;

    foreach (var item in query.Take(5))
    {
        ShowProcess(item);
    }
}

public static void Write(string caption, string data)
{
    Console.WriteLine("{0}: {1}", caption, data);
}

public static void Write(string caption, long data)
{
    Write(caption, string.Format("{0:N0}", data));
}

public static void ShowProcess(Process process)
{
    ShowTitle(process.ProcessName);
    Write("MainWindowTitle", process.MainWindowTitle);
    Write("VirtualMemorySize64", process.VirtualMemorySize64);
}

Listing 17.3. The Output from the Code Shown in Listing 17.2

=================
sqlservr
=================
MainWindowTitle:
VirtualMemorySize64: 1,630,756,864
=================

WINWORD
=================
MainWindowTitle: Chapter16 Advanced LINQ0.docx - Microsoft Word
VirtualMemorySize64: 473,960,448
=================
VCSExpress
=================
MainWindowTitle: ProcessScan - Microsoft Visual C# 2008 Express Edition
VirtualMemorySize64: 438,231,040
=================
explorer
=================
MainWindowTitle:
VirtualMemorySize64: 420,114,432
=================
Zune
=================
MainWindowTitle: Zune
VirtualMemorySize64: 412,151,808

The query shown in this example is very simple:

var query = from p in Process.GetProcesses()
            orderby p.VirtualMemorySize64 descending
            select p;

The Process class supports a method called GetProcesses that retrieves all the programs running on your system. You can see the same list of programs in the Windows Task Manager.

In our query, the LINQ OrderBy operator is used to sort the items retrieved in descending order by the amount of memory they take up. The resulting list is quite interesting, because it gives you a sense of which programs are using the most memory on your system.

Here is the declaration for System.Diagnostics.Process.GetProcesses:

public static Process[] GetProcesses();

This method returns an array of Processes. As mentioned in Chapter 4, “C# 3.0 Technical Overview,” the developers of C# and .NET ensured that arrays are fully queryable by LINQ. The Base Class Library (BCL) has no array type called Process[] or int[]. Instead, the CLR improvises, so to speak, and spins up a new type for you at runtime. These types appear to implement the following set of interfaces:

System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.Generic.IList<T>
System.Collections.Generic.ICollection<T>
System.Collections.Generic.IEnumerable<T>

These types also inherit from System.Array. As you can see, IEnumerable and IEnumerable<T> are supported. As a result, you can query such an array with LINQ.

There really isn’t much else to say about this example. I’ve included it here just as a reminder that sometimes we don’t need to create a fancy LINQ provider just to access a particular data source. Please don’t spend hours trying to create your own LINQ provider when a few simple calls to LINQ to Objects will solve your problem. On the other hand, if you see a real need for a new LINQ provider, and you think you have the time and ability to create it, please get to work as soon as possible, and share your efforts with the community. When you are done, visit the “Links to LINQ” section of my blog, and let me know about your creation so that I can help tell the community about your contribution:

http://blogs.msdn.com/charlie/archive/2006/10/05/Links-to-LINQ.aspx

Summary

In this chapter you have had a look at several different flavors of LINQ. If you look in Appendix A, or follow the URL to my “Links to LINQ” blog post, you will find that there are many other flavors of LINQ that I did not cover in this chapter. Some of them are at least potentially quite important and sophisticated, and others are small projects that have never received much attention put together by a single person. Nevertheless, the extensions to LINQ are a vitally important part of the LINQ story. Hopefully you have found the few examples shown here sufficiently illustrative to encourage you to explore the matter in more depth and perhaps also write your own provider.

Let me wrap up this chapter by taking a moment to stress the importance of this topic. The LINQ providers I’ve described in this chapter are still in prerelease form. Even when they are released, it will probably take several iterations to bring them to maturity. Nevertheless, even as they are now, they are remarkably easy to use, and they show the promise of great power.

The providers described in this chapter extend LINQ so that it can become

• An ideal way to perform concurrent programming by removing many of the impediments that have prevented developers from working with multithreaded applications.

• An easy means of querying a site such as Flickr.

• An easy to use tool for working with the lists found on a SharePoint site.

• An excellent way to perform concurrent programming without having to encounter many of the impediments that have prevented developers from working with multithreaded applications.

We are still at the dawn of the LINQ era. When object-oriented programming first emerged, it was not obvious how important it would become. The same was true of the Web, of multimedia technology, and of many other tools. LINQ came into the world remarkably fully formed, but this chapter only hints at the many ways LINQ can be extended to solve myriad problems. The future of LINQ is bound up with the future of LINQ providers such as the ones described in this chapter. As we witness the development of increasingly powerful and sophisticated LINQ providers for an increasingly large range of data sources, we will see the emergence of an important new technology that will have a significant capability to simplify and improve how we write and maintain our code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset