How to Read Twitter Feeds With LINQ to XML

Twitter feeds are provided in RSS XML format. This makes it very easy for us to parse out the information we want from a feed using LINQ to XML. For example, if we want to grab the message and date of each Twitter entry, we could use something like this:

public class Twitter
{
    public string Message { get; set; }
    public DateTime PubDate { get; set; }

    public static List<Twitter> Parse(string User)
    {
        var rv = new List<Twitter>();
        var url = "http://twitter.com/statuses/user_timeline/" + User + ".rss";
 
        var element = XElement.Load(url);
        foreach (var node in element.Element("channel").Elements("item"))
        {
            var twit = new Twitter();
            var message = node.Element("description").Value;

            //remove username information
            twit.Message = message.Replace(User + ": ", string.Empty);
            twit.PubDate = DateTime.Parse(node.Element("pubDate").Value);
            rv.Add(twit);
        }

        return rv;
    }
}

 

You can get the twitter feeds by using the following:

		var fromTwitter = Twitter.Parse("Merlin981");
	

 

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Use a C# Regex MatchCollection With LINQ

Here is a code snippet which accomplishes these following goals:

  • It marries a C# Regular Expression MatchCollection to a property list using Linq.
  • It uses a Regex Pattern which creates named capture groups which Linq can easily exploit in the join of two data lists.

Let me show you the code. Don’t get hung up on the pattern or what it is doing. What needs to be known is that the pattern places the data matched into Named Capture Groups of Key and Value. The actual Key value corresponds to a property on a real class. Using reflection we will find that property on the class and link its property name to the value stored. That will allow us to change that properties value on the class from the Value we get from the regex match.

The goal of the Linq code is to join into another list, which is the list of properties from the class and the commonality is the PropertyInfo.Name found in that list. Once that data is joined a new object will be created which will have the actual property object and the value of Value. That new list will allow the following operations to set target properties value to Value of the match in Match collection.

   1: public static T ASCIISerializeOut<T>( string targetSerialized )

   2:     where T : new()

   3: {

   4:

   5:     T targetInstance = new T();

   6:

   7:     string pattern = string.Format( @"(?<Key>[^{0}]*)(?:{0})(?<Value>[^{1}]*)(?:{1}?)",

   8:                                     Seperators.cnKVPSeperator,   // "±"

   9:                                     Seperators.cnSeperator );    // "¶"

  10:

  11:     MatchCollection mcKVPs = Regex.Matches( targetSerialized,

  12:                                             pattern,

  13:                                             RegexOptions.Compiled );

  14:

  15:     var kvps = from Match m in mcKVPs

  16:                where mcKVPs != null

  17:                where mcKVPs.Count > 0

  18:                join prp in GetPublicProperties<T>() on m.Groups["Key"].Value equals prp.Name

  19:                select new

  20:                {

  21:                    prop  = prp,

  22:                    Value = m.Groups["Value"].Value ?? string.Empty

  23:                };

  24:

  25:     foreach (var item in kvps)

  26:         item.prop.SetValue( targetInstance, item.Value, null );

  27:

  28:     return targetInstance;

  29:

  30: }

  31:

  32: /// <summary>

  33: /// Return all public properties which are of string type from T class.

  34: /// </summary>

  35: public static IEnumerable<PropertyInfo> GetPublicProperties<T>()

  36: {

  37:     return from p in typeof( T ).GetProperties()

  38:            where p.PropertyType == typeof( string )

  39:            select p;

  40: }

  • Line 01: The function takes in text such as “AProp±AValue¶BProp±BValue” which needs to be serialized into a newly created class of type T. The first item in the pattern is the property name AProp followed by a seperator ± then the value of the property AValue and finally a key value seperator: ¶. our regex will create individual matches for each of the key value pairs.
  • Line 07: This pattern when used will get key and value pair combinations and place them in named groups of Key and Value of the match.
  • Line 11: Get all the key/value pair combinations into the match collection.
  • Line 15: Linq starts here: We define a Var object kvps (key value pairs) which will use /loop each match from the match collection.
  • Line 16: Make sure the collection is not null.
  • Line 17: Make sure there are one or more matches.
  • Line 18: Get all the public properties of class T and make a join to our collection data. Key should match the property Name.
  • Line 19: Each match found within the property where the names are the same will create this new object below with two properties.
  • Line 21: Save the actual property object, we need that later to load data.
  • Line 22: Get the value out of the Value group and save that as well. Note, if it is null, just use string.Empty. Thanks Null Coalescing operation (??).
  • Line 25: Now for each var object created enumerate through it and load the target values into our newly minted class object of T.
  • Line 26: Set the target item’s property to the value found from the regex matches.
  • Line 28: Return the new object with the original text data serialized in.
  • Line 35: Return an enumeration of all generic string properties of the type T.
GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

Sponsor – Score Your Dreamprize and Win $50,000

cash2 Sponsor   Score Your Dreamprize and Win $50,000

Solow, makers of cool ringtones and other phone accessories, is running a special contest for the next month. You can win any number of prizes during the contest,
from a new car, new phones (like an iPhone of G1 Android). Every time
you play you’re entered into the drawing to win $50,000 at the end of
the month. You can enter 20 times per day, which gives you 20 chances
to win – every day!

Score Your Dreamprize and Win $50,000

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Page LINQ to SQL with a LinqDataSource Control

Undoubtedly,
anyone who has evaluated LINQ to SQL has fond it a fairly powerful yet
lightweight ORM technology which is less complex than the ADO Entity
Framework yet utilizes the strength and power of Language Integrated
Queries.

One problem with LINQ to SQL is the auto paging
feature of the LinqDataSource.  Below is a rough GridView which
displays three columns, UserName, FirstName and LastName.  This is just
a rough demo, so we’re looking at paging.

     image

If
you simply drop a GridView and a LinqDataSource control onto a Web Form
and configure the LinqDataSource (using Smart Tags) without specifying
a Group By field or Order By field (Figure 1) then you will get fairly
optimal database querying (Figure 2) although without any ordering.

     image 
     Figure 1: Configure Linq Data Source

     image 
     Figure 2: SQL Trace of a page load

While
it is great for lightweight or simple applications, it’s rather
unacceptable for use in anything serious (especially with more complex
queries). 

Should you supply a Group By/Order By field,
the LinqDataSource control will query for a RowCount before executing a
single query for each row in the range, i.e. if Page Count is 10, it
will execute 10 queries after the initial row query (Figure 3). 

     trace-1
     Figure 3: SQL Trace when using Group By

This occurs when you choose to use a group by/order by sort – The select clause of the LinqDataSource becomes:

     GroupBy="UserName" OrderGroupsBy="key" Select="new (key as UserName, it as Users)"

Obviously we’d like decent performance and
the ability to sort/group our data.  So there is a pretty low-overhead
solution.  The first (obvious) step is to disable the LinqDataSource
AutoPage property.  The next is to implement an event for
LinqDataSource’s OnSelecting event, as so:  (note: I’ve included the
GridView for reference)

<form id="form1" runat="server">

  <asp:GridView ID="UserGridView" runat="server" AllowPaging="True"
      DataSourceID="UserLinqDataSource" AutoGenerateColumns="False">
      <Columns>
          <asp:BoundField DataField="UserName" HeaderText="UserName" ReadOnly="True"
              SortExpression="UserName" />
               <asp:BoundField DataField="FirstName" HeaderText="FirstName"
              SortExpression="FirstName" />
               <asp:BoundField DataField="LastName" HeaderText="LastName"
              SortExpression="LastName" />
      </Columns>
  </asp:GridView>

  <asp:LinqDataSource ID="UserLinqDataSource" runat="server" AutoPage="False"
      ContextTypeName="DataAccess.DataClassesDataContext"
      OnSelecting="UserLinqDataSourceSelecting"
      Select="new (UserName, FirstName, LastName)" TableName="Users">
  </asp:LinqDataSource>

</form>

 

Now for our code behind, we only need to implement the Selecting event, and we have our smarter paging enabled.

                /// <summary>
        /// Implements Server Side Paging for the LinqDataSource
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void UserLinqDataSourceSelecting(object sender, LinqDataSourceSelectEventArgs e)
        {
            /*
             When AutoPage is false, LinqDataSource requires that the user handle the paging
             manually during the Selecting event.  In this case, you need to set
             DataSourceSelectArguments.TotalRowCount yourself and perform the paging manually

             using DataSourceSelectArguments.StartRowIndex and            
             DataSourceSelectArguments.MaximumRows (pageSize).
            */         

            e.Arguments.StartRowIndex = 0;
            e.Arguments.MaximumRows = 10;                //add your paging limit requirement here
            DataClassesDataContext dc = new DataClassesDataContext();

            e.Arguments.TotalRowCount = dc.Users.Count();   //you could store this value or cache
                                                            //it to avoid the extra DB hit

            //uses an example of ten records/page modify to fit your own paging
            //requirements                                
            e.Result = (from i in dc.Users select i).Skip(UserGridView.PageIndex * 10).Take(10);

            //uses Linq’s Skip() and Take() functions to select a sub section
        }

Let’s take a look at the SQL profile trace, just to be sure:

     image
     Figure 4: New SQL Trace with custom paging

So
this is just a simple little scenario.  It’s nothing big.  It might
help some people out there who are looking to use LinqDataSource but
don’t like the overhead of the Auto Paging.  You’d probably also need
to take a look at supporting sorting (which would need to be factored in to the custom paging query).

This entry doesn’t discuss management of Data Contexts
or a plethora of other considerations which you should take into
consideration before implementing a solution.  Please plan ahead
accordingly before choosing an approach.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

7 LINQ Tricks to Simplify Your Programs

Ever since I learned about LINQ, I keep discovering new ways to use
it to improve my code. Every trick makes my code a little bit faster to
write, and a little bit easier to read.

This posting summarizes some of the tricks that I came across. I will show you how to use LINQ to:

If you have your own bag of LINQ tricks, please share them in the comments!

1. Initialize an array 

Often, you need to initialize elements of an array to either the
same value, or to an increasing sequence values, or possibly to a
sequence increasing or decreasing by a step different from one. With
LINQ, you can do all of this within the array initializer – no for
loops necessary!

In the following code sample, the first line initializes a to an
array of length 10 with all elements set to -1, the second line
initializes b to (0,1,..9), and the third line initializes c to
(100,110,…,190):

int[] a = Enumerable.Repeat(-1, 10).ToArray();
int[] b = Enumerable.Range(0, 10).ToArray();
int[] c = Enumerable.Range(0, 10).Select(i => 100 + 10 * i).ToArray();

A word of caution: if you are initializing large arrays, you may
want to forego the elegance and use the old-fashioned for loop instead.
The LINQ solution will grow the array dynamically, so garbage arrays
will need to be collected by the runtime. That said, I use this trick
all the time when initializing small arrays, or in testing/debugging
code.

2. Iterate over multiple arrays in a single loop 

A friend asked me a C# question: is there a way to iterate over
multiple collections with the same loop? His code looked something like
this:

foreach (var x in array1) {
DoSomething(x);
}
foreach (var x in array2) {
DoSomething(x);
}

In his case, the loop body was larger, and he did not like the
duplicated code. But, he also did not want to allocate a new array to
hold elements from both array1 and array2.

LINQ provides an elegant solution to this problem: the Concat
operator. You can rewrite the above two loops with a single loop as
follows:

foreach (var x in array1.Concat(array2)) {
DoSomething(x);
}

Note that since LINQ operates at the enumerator level, it will not
allocate a new array to hold elements of array1 and array2. So, on top
of being rather elegant, this solution is also space-efficient.

3. Generate a random sequence 

This is a simple trick to generate a random sequence of length N:

Random rand = new Random();
var randomSeq = Enumerable.Repeat(0, N).Select(i => rand.Next());

Thanks to the lazy nature of LINQ, the sequence is not pre-computed
and stored in an array, but instead random numbers are generated
on-demand, as you iterate over randomSeq.

4. Generate a string 

LINQ is also a nice tool to generate various kinds of strings. I
found this quite useful to generate strings for testing and debugging
purposes.

Let’s say that you want to generate a string with the repeating
pattern "ABCABCABC…" of length N. Using LINQ, the solution is quite
elegant:

string str = new string(
Enumerable.Range(0, N)
.Select(i => (char)('A' + i % 3))
.ToArray());

[EDIT] Petar Petrov suggested another interesting way to
generate strings with LINQ. His approach applies to different scenarios
than my solution above:

string values = string.Join(string.Empty, Enumerable.Repeat(pattern, N).ToArray());

5. Convert sequences or collections 

One thing you cannot do in C# or VB is to cast a sequence of type T
to a sequence of type U, even if T us a derived class from U. So, you
cannot just simply cast List<string> to List<object>. (For
an explanation why, see Bick Byers’ posting).

But, if you are trying to convert IEnumerable<T> to
IEnumerable<U>, LINQ has a simple and efficient solution for you:

IEnumerable<string> strEnumerable = ...;
IEnumerable<object> objEnumerable = strEnumerable.Cast<object>();

If you need to convert List<T> to List<U>, there is also a simple LINQ solution, but it involves copying the list:

List<string> strList = ...;
List<object> objList = strList.Cast<object>().ToList();

6. Convert a value to a sequence of length 1 

When you need to convert a single value to a sequence of length 1,
what do you do? You could construct an array of length 1, but I prefer
the LINQ Repeat operator:

IEnumerable<int> seq = Enumerable.Repeat(myValue, 1);

7. Iterate over all subsets of a sequence 

Sometimes it is useful to iterate over all subsets of an array. This
situation arises quite frequently in brute-force solutions to hard
problems. For small inputs, subset sum, boolean satisfiability and the knapsack problem can all be solved easily by iterating over all subsets of some sequence.

In LINQ, we can generate all subsets of array arr as follows:

T[] arr = ...;
var subsets = from m in Enumerable.Range(0, 1 << arr.Length)
select
from i in Enumerable.Range(0, arr.Length)
where (m & (1 << i)) != 0
select arr[i];

Note that if the number of subsets overflows an int, the above code
will not work. So, only use it if you know that the length of arr is at
most 30. If the length of arr is greater than 30, chances are that you
don’t want to iterate over all of its subsets anyway because it is
going to take minutes or more.

 

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How To Query Data with Parallel LINQ

This post shows a simple way to write code that takes advantage of
multiple processors. You will see that LINQ queries can allow you to
side step the difficult tasks normally involved in writing
multi-threaded code. To get started, all you need is a little basic
knowledge of how to write simple LINQ queries.

The code shown
in this post uses a pre-release 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 website for the Parallel Computing team:

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

At
the time of this writing, these extensions were available only in
pre-release form. You could download them either as Visual Studio 2008
compatible extensions to .NET 3.5, or as part of the pre-release
version of Visual Studio 2010. Since the download sites might change
over the coming months, I suggest that you find these resources by
going to the Parallel Computing site, or to 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. Since it is a simple
and natural extension of the LINQ syntax, I think developers familiar
with that technology will find it easy to use.

Consider this code:

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 in many
simple LINQ samples. The only significant difference is the call to AsParallel
at the end of the first line. Though we have often used type inference
to hide the return type of a LINQ query, I'm going to 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 pre-release phase, and let the compiler choose
the type. That way you can save typing, avoid problems with anonymous
types, and you need not concern yourself about changes in the API as
the product develops. It is almost always appropriate to use var to designate the return type of a LINQ query, and there are only special circumstances when you would do otherwise.

Here are the results from 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 entirely random

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 post 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. Here, for instance, are the results showing an
improvement of 1.33 times when using two processors, and almost two
times when using 4 processors:

2 Processors = 1.44 x improvement:
Linear: 00:00:13.15
Parallels: 00:00:09.10
4 Processors = 1.96 x improvement:
Linear: 00:00:15.00
Parallel: 00:00:07.68

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

This sample program is called FakeWeatherData, and it is available for download from the LINQ Farm on Code Gallery.
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, but 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>
<Sample>
<Year>1970</Year>
<Month>Jan</Month>
<Day>15</Day>
<Temperature>11</Temperature>
</Sample>
  ... Many lines of code omitted here
</Samples>

There is also a simple C# class used by the program to encapsulate the data from the XML file:

class WeatherData
{
public string Year { get; set; }
public string Month { get; set; }
public string Day { get; set; }
public string Temperature { get; set; }
}

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

for (int i = 0; i < NUM_REPS; i++)
{
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

for (int i = 0; i < NUM_REPS; i++)
{
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, 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 just 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,
while 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 in order to begin using it. This does not mean that the
subject is trivial, but 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,
then 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>. Though hardly earthshaking in import, these
calls ensure that the code actually does something, and thus gives
PLINQ scope to take advantage of the multiple processers on your
system.

Simple timers are created to measure the difference between
the standard LINQ query and the PLINQ query. I've also used a method
used in many of Parallel LINQ team's samples for displaying the time
elapsed during a test run:

private static void RunTest()
{
XDocument doc = XDocument.Load("XMLFile1.xml");
Stopwatch sw = new Stopwatch();
sw.Start();
LinqOrdinarie(doc);
sw.Stop();
ShowElapsedTime("Ordinaire", sw.Elapsed);
sw.Reset();
sw.Start();
ParallelLinq(doc);
sw.Stop();
ShowElapsedTime("Parallels", sw.Elapsed);
}
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 pre-release version of PLINQ that I've played
with, I've found it very useful to set up timers to confirm that PLINQ
is actually able to speed up an operation. My record at guessing which
code will benefit from running in parallel is not good, and so I find
that confirming the effectiveness of the code by explicitly measuring
it is worthwhile. You can either use the simple StopWatch class from
the System.Diagnostics namespace, as shown here, or else 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, say 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 will need to be loaded, the relevant types
will need to be JIT compiled, and new threads will need to be spun up,
etc. As a result, many developers see improved performance after they
get past the initial warm-up time.

Though it is very easy to get started with PLINQ, there are
still complexities inherent in the subject that you need to consider.
For instance, PLINQ will sometimes develop 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 post should help you get
started with this powerful and interesting technology. Parallel LINQ is
still in its infancy, but already it provides means of greatly
simplifying tasks that are not normally easy to perform.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Use Compiled Queries in Linq to Sql for High Demand ASP.NET Websites

If you are using Linq to SQL, instead of writing regular Linq Queries, you should be using Compiled Queries.
if you are building an ASP.NET web application that’s going to get
thousands of hits per hour, the execution overhead of Linq queries is
going to consume too much CPU and make your site slow. There’s a
runtime cost associated with each and every Linq Query you write. The
queries are parsed and converted to a nice SQL Statement on *every*
hit. It’s not done at compile time because there’s no way to figure out
what you might be sending as the parameters in the queries during
runtime. So, if you have common Linq to Sql statements like the
following one throughout your growing web application, you are soon
going to have scalability nightmares:

var query = from widget in dc.Widgets
where widget.ID == id && widget.PageID == pageId
select widget;
var widget = query.SingleOrDefault();

There’s a nice blog post by JD Conley that shows how evil Linq to Sql queries are:

1 How to Use Compiled Queries in Linq to Sql for High Demand ASP.NET Websites

You see how many times SqlVisitor.Visit is called to convert
a Linq Query to its SQL representation? The runtime cost to convert a
Linq query to its SQL Command representation is just way too high.

Rico Mariani has a very informative performance comparison of regular Linq queries vs Compiled Linq queries performance:

image

Compiled Query wins on every case.

So, now you know about the benefits of compiled queries. If you are
building ASP.NET web application that is going to get high traffic and
you have a lot of Linq to Sql queries throughout your project, you have
to go for compiled queries. Compiled Queries are built for this
specific scenario.

In this article, I will show you some steps to convert regular Linq
to Sql queries to their Compiled representation and how to avoid the
dreaded exception “Compiled queries across DataContexts with different LoadOptions not supported.”

Here are some step by step instruction on converting a Linq to Sql query to its compiled form:

First we need to find out all the external decision factors in a
query. It mostly means parameters in the WHERE clause. Say, we are
trying to get a user from aspnet_users table using Username and Application ID:

Query to get a user from aspnet_users table

Here, we have two external decision factor – one is the Username and
another is the Application ID. So, first think this way, if you were to
wrap this query in a function that will just return this query as it
is, what would you do? You would create a function that takes the DataContext (dc named here), then two parameters named userName and applicationID, right?

So, be it. We create one function that returns just this query:

Converting a LInq Query to a function

Next step is to replace this function with a Func<> representation that returns the query. This is the hard part. If you haven’t dealt with Func<> and Lambda expression before, then I suggest you read this and this and then continue.

So, here’s the delegate representation of the above function:

Creating a delegate out of Linq Query 

Couple of things to note here. I have declared the delegate as static readonly
because a compiled query is declared only once and reused by all
threads. If you don’t declare Compiled Queries as static, then you
don’t get the performance gain because compiling queries everytime when
needed is even worse than regular Linq queries.

Then there’s the complex Func<DropthingsDataContext, string, Guid, IQueryable<aspnet_User>> thing. Basically the generic Func<> is declared to have three parameters from the GetQuery function and a return type of IQueryable<aspnet_User>. Here the parameter types are specified so that the delegate is created strongly typed. Func<> allows up to 4 parameters and 1 return type.

Next comes the real business, compiling the query. Now that we have the query in delegate form, we can pass this to CompiledQuery.Compile
function which compiles the delegate and returns a handle to us.
Instead of directly assigning the lambda expression to the func, we
will pass the expression through the CompiledQuery.Compile function.

Converting a Linq Query to Compiled Query

Here’s where head starts to spin. This is so hard to read and
maintain. Bear with me. I just wrapped the lambda expression on the
right side inside the CompiledQuery.Compile function. Basically that’s the only change. Also, when you call CompiledQuery.Compile<>, the generic types must match and be in exactly the same order as the Func<> declaration.

Fortunately, calling a compiled query is as simple as calling a function:

Running Compiled Query

There you have it, a lot faster Linq Query execution. The hard work
of converting all your queries into Compiled Query pays off when you
see the performance difference.

Now, there are some challenges to Compiled Queries. Most common one
is, what do you do when you have more than 4 parameters to supply to a
Compiled Query? You can’t declare a Func<> with more than 4 types. Solution is to use a struct to encapsulate all the parameters. Here’s an example:

Using struct in compiled query as parameter

Calling the query is quite simple:

Calling compiled query with struct parameter

Now to the dreaded challenge of using LoadOptions with Compiled Query. You will notice that the following code results in an exception:

Using DataLoadOptions with Compiled Query

 

The above DataLoadOption runs perfectly when you use regular
Linq Queries. But it does not work with compiled queries. When you run
this code and the query hits the second time, it produces an exception:

Compiled queries across DataContexts with different LoadOptions not supported

A compiled query remembers the DataLoadOption once its called. It does not allow executing the same compiled query with a different DataLoadOption again. Although you are creating the same DataLoadOption with the same LoadWith<>
calls, it still produces exception because it remembers the exact
instance that was used when the compiled query was called for the first
time. Since next call creates a new instance of DataLoadOptions, it does not match and the exception is thrown. You can read details about the problem in this forum post.

The solution is to use a static DataLoadOption. You cannot create a local DataLoadOption instance and use in compiled queries. It needs to be static. Here’s how you can do it:

image

 

Basically the idea is to construct a static instance of DataLoadOptions using a static function. As writing function for every single DataLoadOptions
combination is painful, I created a static delegate here and executed
it right on the declaration line. This is in interesting way to declare
a variable that requires more than one statement to prepare it.

Using this option is very simple:

image

Now you can use DataLoadOptions with compiled queries.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Debug LINQ Queries

Debugging LINQ queries can be problematic.  One
of the reasons is that quite often, you write a large query as a single
expression, and you can’t set a breakpoint mid-expression.  Writing
large queries in expression context is particularly powerful when using
functional construction to form XML (or using the strongly typed DOM in
Open XML SDK V2).  This post presents a little
trick that makes it easier to use the debugger with LINQ queries that
are written using ‘method syntax’.

The gist of the technique is to insert a call to the Select extension method in the middle of your query.  You code the Select so that it projects exactly the same results as its source, but using a statement lambda expression  If
you place the return statement of the lambda expression on its own
line, you can set a breakpoint and examine values as they make their
way through the query.

The
following is a query to split a string into words, convert the words to
lower case, count the number of occurances of each word, and return the
ten most used words:

var uniqueWords = text

    .Split(' ', '.', ',')

    .Where(i => i != "")

    .Select(i => i.ToLower())

    .GroupBy(i => i)

    .OrderByDescending(i => i.Count())

    .Select(i => new { Word = i.Key, Count = i.Count() })

    .Take(10);

 

But if you set a breakpoint anywhere on the query, you see this:

LINQ Debug

Let’s say that you want to examine each group and see the group key and the count of items for each group.  You can insert a Select statement, as follows:

var uniqueWords = text

    .Split(' ', '.', ',')

    .Where(i => i != "")

    .Select(i => i.ToLower())

    .GroupBy(i => i)

    .Select(z => {

        return z;

    })

    .OrderByDescending(i => i.Count())

    .Select(i => new { Word = i.Key, Count = i.Count() })

    .Take(10);

 

you
can now set a breakpoint on the ‘return z’ statement, and examine each
group in turn as they are yielded up by the GroupBy extension method:

Debug LINQ Statements

You can see that the key is “on”, and that there are four items in the group.

After you are done debugging, you can remove the added call to Select.

Alternatively,
you could convert any of the other lambda expressions to a statement
lambda expression, format code so that a statement is on its own line,
and then set a breakpoint.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

Using LINQ to Query Excel Tables

Excel has a very cool feature where you can declare that a range of cells is a table.  It is a feature that allows you to use Excel very much like a database.  You can add new rows as necessary, sort the table by columns, do some simple filtering, calculate the sum of columns, and more.  Each table has a unique table name, and each column has a column name.  Because
these tables are stored in Open XML documents, we can implement some
simple extension methods and some classes so that we can query these
tables using LINQ in a manner that is similar to querying a SQL
database.  This post presents a bit of code to do this.  The code and sample documents are attached to this post (
LtxOpenXml.zip (169.21 kb).

Note: this code is presented as an example – a proof-of-concept.  This code could be further optimized, so that it performs better (although it performs quite well as is).  And
it may be interesting in the future to modify the code to use a
strongly-typed approach – as the code is currently implemented, if you
misspell a table or column name, the code throws an exception.  However, this code is useful as is for doing ad-hoc queries of Excel tables.  (I certainly will be using it!
)

This code uses the Open XML SDK, either V1, or the CTP of V2.  You can download V1 of the SDK here.  You can download CTP1 of V2 of the SDK here.

Following is a screen clipping of an Excel spreadsheet that contains a table:

 Using LINQ to Query Excel Tables

You can see the four columns of this table: Item, Qty, Price, and Extension.  In addition, in the Design tab of the ribbon, in the far left box, you can see that this table has a table name of “Inventory”.  Using the code presented in this post, you can query this table as follows:

var query =

    from i in spreadsheet.Table("Inventory").TableRows()

    where (int)i["Qty"] > 2

    select i;

 

foreach (var r in query)

{

    Console.WriteLine(r["Item"]);

    Console.WriteLine(r["Qty"]);

    Console.WriteLine(r["Price"]);

    Console.WriteLine(r["Extension"]);

    Console.WriteLine();

}

 

When you run this code, it produces:

Book

44

2

88

 

Phone

4

10

40

 

As
you can see from the above code, to access a particular column from a
table row, you can use a default indexed property, passing the name of
the column:

Console.WriteLine(r["Item"]);

Console.WriteLine(r["Qty"]);

Console.WriteLine(r["Price"]);

Console.WriteLine(r["Extension"]);

 

This allows us to write code that is easy to read.

The table class (returned by the Table method) has a TableColumns method that iterates the columns in the table:

// list all of the columns in the Inventory table

Console.WriteLine("Table: Inventory");

foreach (var c in spreadsheet.Table("Inventory").TableColumns())

    Console.WriteLine("  {0}", c.Name);

 

When you run this code, you see:

Table: Inventory

  Item

  Qty

  Price

  Extension

 

The LtxOpenXml Namespace

Some time ago, I wrote some code that enabled querying Open XML spreadsheets using LINQ to XML, presented in the blog post ‘Open XML SDK and LINQ to XML’.  I’ve added the code to query tables to the code presented in that post.  The extension methods that enable querying tables make use of that code.  The enhanced LtxOpenXml namespace now contains code for:

  • Querying word processing documents
  • Querying spreadsheets
  • Querying tables contained in spreadsheets

The code for querying word processing documents and spreadsheets is unmodified.  Refer to the above mentioned blog post for details on using those extension methods.

The code that enables querying of spreadsheet tables is, of course, written in the pure functional style.  No state is maintained, and all methods to query the document are lazy.

If
you have questions about how to write functional code (like the code
that implements the extension methods and classes associated with this
post), go through this
Functional Programming Tutorial.

I’ve provided a summary of the types and extension methods included in the LtxOpenXml namespace at the end of this post.

Use of Data Types

Here’s another example of a table that contains a few more columns with more data types:

 Using LINQ to Query Excel Tables

Each row returned by the TableRows method is a collection of TableCell objects.  I’ve
defined explicit conversions between TableCell and some of the most
common .NET types, so that you can simply cast a TableCell to your
desired type.  Here’s a query to list all vehicles in the table:

// list all vehicles

var q = from c in spreadsheet.Table("Vehicles").TableRows()

        select new VehicleRecord()

        {

            Vehicle = (string)c["Vehicle"],

            Color = (string)c["Color"],

            Year = (int)c["Year"],

            HorsePower = (int)c["HorsePower"],

            Cost = (decimal)c["Cost"],

            AcquisitionDate = (DateTime)c["AcquisitionDate"],

            ExecutiveUseOnly = (bool)c["ExecutiveUseOnly"]

        };

 

Console.WriteLine("List of all vehicles");

PrintVehicles(q);

Console.WriteLine();

 

I’ve written a PrintVehicles method:

public static void PrintVehicles(IEnumerable<VehicleRecord> list)

{

    int[] tabs = new[] { 12, 10, 6, 6, 10, 14, 10 };

    foreach (var z in list)

        Console.WriteLine("{0}{1}{2}{3}{4}{5}{6}",

            z.Vehicle.PadRight(tabs[0]),

            z.Color.PadRight(tabs[1]),

            z.Year.ToString().PadRight(tabs[2]),

            z.HorsePower.ToString().PadRight(tabs[3]),

            z.Cost.ToString().PadRight(tabs[4]),

            ((DateTime)z.AcquisitionDate).ToShortDateString()

                .PadRight(tabs[5]),

            ((bool)z.ExecutiveUseOnly).ToString()

                .PadRight(tabs[6]));

}

 

When you run the above query, you see:

List of all vehicles

Pickup      White     2002  165   23000     2/22/2002     False

Pickup      Red       2004  185   32000     10/21/2004    False

Sports Car  Red       2003  165   23000     1/1/2004      True

Sedan       Blue      2005  200   21000     2/25/2005     False

Limo        Black     2008  440   72000     4/1/2008      True

 

You can query for all executive vehicles, like this:

// list all executive vehicles

q = from c in spreadsheet.Table("Vehicles").TableRows()

        where (bool)c["ExecutiveUseOnly"] == true

        select new VehicleRecord()

        {

            Vehicle = (string)c["Vehicle"],

            Color = (string)c["Color"],

            Year = (int)c["Year"],

            HorsePower = (int)c["HorsePower"],

            Cost = (decimal)c["Cost"],

            AcquisitionDate = (DateTime)c["AcquisitionDate"],

            ExecutiveUseOnly = (bool)c["ExecutiveUseOnly"]

        };

 

You can write queries that select on data types such as DateTime:

// list all vehicles acquired after 2004

q = from c in spreadsheet.Table("Vehicles").TableRows()

    where (DateTime)c["AcquisitionDate"] >= new DateTime(2004, 1, 1)

    select new VehicleRecord()

    {

        Vehicle = (string)c["Vehicle"],

        Color = (string)c["Color"],

        Year = (int)c["Year"],

        HorsePower = (int)c["HorsePower"],

        Cost = (decimal)c["Cost"],

        AcquisitionDate = (DateTime)c["AcquisitionDate"],

        ExecutiveUseOnly = (bool)c["ExecutiveUseOnly"]

    };

 

And of course, you can use all of the grouping, ordering, and filtering capabilities of LINQ queries:

// vehicles grouped by user

var groups = from v in spreadsheet.Table("Vehicles").TableRows()

             group v by v["ExecutiveUseOnly"];

 

foreach (var g in groups)

{

    Console.WriteLine("Executive Use: {0}", (bool)g.Key);

    foreach (var v in g)

        Console.WriteLine("  Vehicle:{0}  Year:{1}",

            v["Vehicle"], v["Year"]);

    Console.WriteLine();

}

 

I’ve
imported the Customers and Orders from the Northwind database into a
spreadsheet, where the Customers table is in one sheet, and the Orders
table is in another sheet within the worksheet.  Here is the Customers table:

 Using LINQ to Query Excel Tables

And here is the Orders table:

 Using LINQ to Query Excel Tables

We can now write a query that joins the customers and orders tables:

using (SpreadsheetDocument spreadsheet =

    SpreadsheetDocument.Open(filename, false))

{

    // list all of the columns in the Customer table

    Console.WriteLine("Table: Customer");

    foreach (var c in spreadsheet.Table("Customer").TableColumns())

        Console.WriteLine("  {0}", c.Name);

    Console.WriteLine();

 

    // list all of the columns in the Order table

    Console.WriteLine("Table: Order");

    foreach (var o in spreadsheet.Table("Order").TableColumns())

        Console.WriteLine("  {0}", o.Name);

    Console.WriteLine();

 

    // query for all customers with city == London,

    // then select all orders for that customer

    var q = from c in spreadsheet.Table("Customer").TableRows()

            where (string)c["City"] == "London"

            select new

            {

                CustomerID = c["CustomerID"],

                CompanyName = c["CompanyName"],

                ContactName = c["ContactName"],

                Orders = from o in spreadsheet.Table("Order").TableRows()

                         where (string)o["CustomerID"] ==

                               (string)c["CustomerID"]

                         select new

                             {

                                 CustomerID = o["CustomerID"],

                                 OrderID = o["OrderID"]

                             }

            };

 

    // print the results of the query

    int[] tabs = new[] { 20, 25, 30 };

    Console.WriteLine("{0}{1}{2}",

        "CustomerID".PadRight(tabs[0]),

        "CompanyName".PadRight(tabs[1]),

        "ContactName".PadRight(tabs[2]));

    Console.WriteLine("{0} {1} {2} ", new string('-', tabs[0] – 1),

        new string('-', tabs[1] – 1), new string('-', tabs[2] – 1));

    foreach (var v in q)

    {

        Console.WriteLine("{0}{1}{2}",

            v.CustomerID.Value.PadRight(tabs[0]),

            v.CompanyName.Value.PadRight(tabs[1]),

            v.ContactName.Value.PadRight(tabs[2]));

        foreach (var v2 in v.Orders)

            Console.WriteLine("  CustomerID:{0}  OrderID:{1}",

                v2.CustomerID, v2.OrderID);

        Console.WriteLine();

    }

}

 

This code produces the following output:

Table: Customer

  CustomerID

  CompanyName

  ContactName

  ContactTitle

  Address

  City

  Region

  PostalCode

  Country

  Phone

  Fax

 

Table: Order

  OrderID

  CustomerID

  EmployeeID

  OrderDate

  RequiredDate

  ShipVia

  Freight

  ShipName

  ShipAddress

  ShipCity

  ShipRegion

  ShipPostalCode

  ShipCountry

 

CustomerID          CompanyName              ContactName

——————- ———————— —————————–

AROUT               Around the Horn          Thomas Hardy

  CustomerID:AROUT  OrderID:10355

  CustomerID:AROUT  OrderID:10383

  CustomerID:AROUT  OrderID:10453

  CustomerID:AROUT  OrderID:10558

  CustomerID:AROUT  OrderID:10707

  CustomerID:AROUT  OrderID:10741

  CustomerID:AROUT  OrderID:10743

  CustomerID:AROUT  OrderID:10768

  CustomerID:AROUT  OrderID:10793

  CustomerID:AROUT  OrderID:10864

  CustomerID:AROUT  OrderID:10920

  CustomerID:AROUT  OrderID:10953

  CustomerID:AROUT  OrderID:11016

 

BSBEV               B's Beverages            Victoria Ashworth

  CustomerID:BSBEV  OrderID:10289

  CustomerID:BSBEV  OrderID:10471

  CustomerID:BSBEV  OrderID:10484

  CustomerID:BSBEV  OrderID:10538

  CustomerID:BSBEV  OrderID:10539

  CustomerID:BSBEV  OrderID:10578

  CustomerID:BSBEV  OrderID:10599

  CustomerID:BSBEV  OrderID:10943

  CustomerID:BSBEV  OrderID:10947

  CustomerID:BSBEV  OrderID:11023

 

CONSH               Consolidated Holdings    Elizabeth Brown

  CustomerID:CONSH  OrderID:10435

  CustomerID:CONSH  OrderID:10462

  CustomerID:CONSH  OrderID:10848

 

EASTC               Eastern Connection       Ann Devon

  CustomerID:EASTC  OrderID:10364

  CustomerID:EASTC  OrderID:10400

  CustomerID:EASTC  OrderID:10532

  CustomerID:EASTC  OrderID:10726

  CustomerID:EASTC  OrderID:10987

  CustomerID:EASTC  OrderID:11024

  CustomerID:EASTC  OrderID:11047

  CustomerID:EASTC  OrderID:11056

 

NORTS               North/South              Simon Crowther

  CustomerID:NORTS  OrderID:10517

  CustomerID:NORTS  OrderID:10752

  CustomerID:NORTS  OrderID:11057

 

SEVES               Seven Seas Imports       Hari Kumar

  CustomerID:SEVES  OrderID:10359

  CustomerID:SEVES  OrderID:10377

  CustomerID:SEVES  OrderID:10388

  CustomerID:SEVES  OrderID:10472

  CustomerID:SEVES  OrderID:10523

  CustomerID:SEVES  OrderID:10547

  CustomerID:SEVES  OrderID:10800

  CustomerID:SEVES  OrderID:10804

  CustomerID:SEVES  OrderID:10869

 

Summary of the LtxOpenXml Namespace

This section summarizes the LtxOpenXml extension methods and types that make it easy to work with Open XML SpreadsheetML tables.

For
details on the extension methods and types for word processing
documents and spreadsheets (other than Tables within spreadsheets), see
the post,
Open XML SDK and LINQ to XML.

Tables Extension Method

This method returns a collection of all tables in the spreadsheet.  Its signature:

public static IEnumerable<Table> Tables(this SpreadsheetDocument spreadsheet)

 

Table Extension Method

This method returns the Table object with the specified table name.  Its signature:

public static Table Table(this SpreadsheetDocument spreadsheet,

    string tableName)

 

Table Class

This method represents an Excel Table.  Its definition:

public class Table

{

    public int Id { get; set; }

    public string TableName { get; set; }

    public string DisplayName { get; set; }

    public string Ref { get; set; }

    public int? HeaderRowCount { get; set; }

    public int? TotalsRowCount { get; set; }

    public string TableType { get; set; }

    public TableDefinitionPart TableDefinitionPart { get; set; }

    public WorksheetPart Parent { get; set; }

    public Table(WorksheetPart parent) { Parent = parent; }

    public IEnumerable<TableColumn> TableColumns()

    {

       

    }

    public IEnumerable<TableRow> TableRows()

    {

       

    }

}

 

This class contains a number of properties about the table.  In
addition, it contains two methods, TableColumns, which returns a
collection of TableColumn objects (the columns of the table), and
TableRows, which returns a collection of TableRow objects (the rows of
the table).

TableColumn Class

This class represents a column of a table.  Its definition:

public class TableColumn

{

    public int Id { get; set; }

    public string Name { get; set; }

    public int? FormatId { get; set; }  // dataDxfId

    public int? QueryTableFieldId { get; set; }

    public string UniqueName { get; set; }

    public Table Parent { get; set; }

    public TableColumn(Table parent) { Parent = parent; }

}

 

The most important property of this class is the Name property.

TableRow Class

This class represents a row of a table.  Its definition:

public class TableRow

{

    public Row Row { get; set; }

    public Table Parent { get; set; }

    public TableRow(Table parent) { Parent = parent; }

    public TableCell this[string columnName]

    {

        get

        {

           

        }

    }

}

 

The
most important feature of this class is the default indexed property
that takes a column name and returns a TableCell object.  This is what allows us to write code like this:

Console.WriteLine(r["Item"]);

Console.WriteLine(r["Qty"]);

Console.WriteLine(r["Price"]);

Console.WriteLine(r["Extension"]);

 

TableCell Class

This class represents a cell of a row of a table.  It implements IEquatable<T> so that you can do a value compare of two cells.  It also implements a number of explicit conversions to other data types so that it’s easy to deal with columns of various types.  Its definition:

public class TableCell : IEquatable<TableCell>

{

    public string Value { get; set; }

    public TableCell(string v)

    {

        Value = v;

    }

    public override string ToString()

    {

        return Value;

    }

    public override bool Equals(object obj)

    {

        return this.Value == ((TableCell)obj).Value;

    }

    bool IEquatable<TableCell>.Equals(TableCell other)

    {

        return this.Value == other.Value;

    }

    public override int GetHashCode()

    {

        return this.Value.GetHashCode();

    }

    public static bool operator ==(TableCell left, TableCell right)

    {

        if ((object)left != (object)right) return false;

        return left.Value == right.Value;

    }

    public static bool operator !=(TableCell left, TableCell right)

    {

        if ((object)left != (object)right) return false;

        return left.Value != right.Value;

    }

    public static explicit operator string(TableCell cell)

    {

        if (cell == null) return null;

        return cell.Value;

    }

    public static explicit operator bool(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return cell.Value == "1";

    }

    public static explicit operator bool?(TableCell cell)

    {

        if (cell == null) return null;

        return cell.Value == "1";

    }

    public static explicit operator int(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return Int32.Parse(cell.Value);

    }

    public static explicit operator int?(TableCell cell)

    {

        if (cell == null) return null;

        return Int32.Parse(cell.Value);

    }

    public static explicit operator uint(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return UInt32.Parse(cell.Value);

    }

    public static explicit operator uint?(TableCell cell)

    {

        if (cell == null) return null;

        return UInt32.Parse(cell.Value);

    }

    public static explicit operator long(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return Int64.Parse(cell.Value);

    }

    public static explicit operator long?(TableCell cell)

    {

        if (cell == null) return null;

        return Int64.Parse(cell.Value);

    }

    public static explicit operator ulong(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return UInt64.Parse(cell.Value);

    }

    public static explicit operator ulong?(TableCell cell)

    {

        if (cell == null) return null;

        return UInt64.Parse(cell.Value);

    }

    public static explicit operator float(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return Single.Parse(cell.Value);

    }

    public static explicit operator float?(TableCell cell)

    {

        if (cell == null) return null;

        return Single.Parse(cell.Value);

    }

    public static explicit operator double(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return Double.Parse(cell.Value);

    }

    public static explicit operator double?(TableCell cell)

    {

        if (cell == null) return null;

        return Double.Parse(cell.Value);

    }

    public static explicit operator decimal(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return Decimal.Parse(cell.Value);

    }

    public static explicit operator decimal?(TableCell cell)

    {

        if (cell == null) return null;

        return Decimal.Parse(cell.Value);

    }

    public static implicit operator DateTime(TableCell cell)

    {

        if (cell == null) throw new ArgumentNullException("TableCell");

        return new DateTime(1900, 1, 1).AddDays(Int32.Parse(cell.Value) – 2);

    }

    public static implicit operator DateTime?(TableCell cell)

    {

        if (cell == null) return null;

        return new DateTime(1900, 1, 1).AddDays(Int32.Parse(cell.Value) – 2);

    }

}

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

Merry Christmas

I'll be on and off line for the next few days, so there may not be a new Linq Exchange post until Jan 2.

Have a Merry Holiday (please substitute the appropriate holiday you celebrate, here), and Happy New Year.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark
 Page 4 of 9  « First  ... « 2  3  4  5  6 » ...  Last »