LP on .NET

May 18, 2010

Don’t Fall into the Outer Variable Trap

Filed under: .NET,C#,LINQ,Software Development — Larry Parker @ 9:54 pm

Today I needed to loop through a collection and call a method on each of its items.  This was inside a service call that needed to return quickly, which meant that the methods would be called asynchronously.

So I queued up the tasks on the thread pool and was done:

foreach (Manager mgr in ManagerList)
    ThreadPool.QueueUserWorkItem(o => mgr.DoIt());

Very simple.

But when I ran it, I found that the DoIt method was only called on the last item in the list and was called repetitively (once for each item in the collection).

What happened here?  The code looks like it should work!

This is a common pitfall when using outer variables and is sometimes referred to as the “outer variable trap”.

The problem here is that there’s actually a race condition since the value of the outer variable “mgr” is important at the time the work item is actually executed.

The reason the behavior is erratic is because “mgr” is an outer variable referred to by the lambda expression passed to QueueUserWorkItem, but when the lambda expression is actually evaluated the value of mgr may have changed.

So instead of relying on an outer variable and lucky timing, the correct approach is to pass the outer variable into QueueUserWorkItem and then have the lambda expression call the DoIt method on its local variable.

foreach (Manager mgr in ManagerList)
    ThreadPool.QueueUserWorkItem(o => (o as Manager).DoIt(), mgr);

This works because “mgr” is passed into QueueUserWorkItem and is exactly what the local variable “o” inside the lambda expression refers to.  We need to cast it to the Manager class because QueueUserWorkItem’s WaitCallback delegate uses an Object in its signature.

So be careful of outer variable semantics and avoid the trap.  They can cause lots of trouble because you may think your code will run a certain way but in actuality it could be doing something very different.

Hope this helps.

June 17, 2009

LINQ Queries the Easy Way

Filed under: .NET,LINQ,SQL Server — Larry Parker @ 1:14 pm

A colleague recently approached me about a LINQ query he wrote that was a bit challenging since it traversed about a half dozen tables in the database.  He had it working but it was very long (several dozen lines) and he was curious if there was a better way.

The query he wrote used the LINQ query syntax instead of the method syntax (sometimes called lambda syntax) .  Query syntax tends to be a bit verbose, while method syntax can be a bit cryptic at times (see here for a comparison of the two styles).  I can’t really say one is “better” than the other, and I find that I use both in many cases, sometimes within the same query.

But more importantly, he was doing joins the “old” way — i.e. his LINQ code looked very much like SQL code.  When I started writing LINQ queries, I took the same approach.  SQL was familiar to me so being able to write strongly-typed SQL code in LINQ was at least a step up.  But writing queries this way is not thinking in LINQ.

I will demonstrate a query that is along the lines of how we ended up translating his original query into something very simple that flowed very nicely.  (His new query ended up being four lines of code instead of the original several dozen.)

Using the ever awesome LINQPad utility as our development environment, and coding against the Northwind database, we have the following challenge:

Retrieve the customer ID and company name for all customers who have ever placed an order that contained a product in the Condiments category.

LINQPad queries execute within the context of the database context, so I won’t be prefixing anything with “db”, “dc”, “ctx”, etc.

The first step is to just get the customer ID and company name:

Customers.Select(o => new {o.CustomerID, o.CompanyName})

This returns 91 rows and generates the following SQL:

SELECT [t0].[CustomerID], [t0].[CompanyName]
FROM [Customers] AS [t0]

Next, we refine the query to only get customers who have placed an order:

Customers.Where(o => o.Orders.Any())
    .Select(o => new {o.CustomerID, o.CompanyName})

This returns 88 rows and generates the following SQL:

SELECT [t0].[CustomerID], [t0].[CompanyName]
FROM [Customers] AS [t0]
WHERE EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [Orders] AS [t1]
    WHERE [t1].[CustomerID] = [t0].[CustomerID]
    )

Notice how the LINQ Any operator was translated into a SQL “WHERE EXISTS”.

Now things get a bit more complicated because we only want orders that contain condiments, but the query still flows very nicely:

Customers.Where(o => o.Orders.Any(o2 => o2.OrderDetails
    .Any(o3 => o3.Product.Category.CategoryName == "Condiments")))
    .Select(o => new {o.CustomerID, o.CompanyName})

The final result set is 68 customers, with the SQL looking like this:

SELECT [t0].[CustomerID], [t0].[CompanyName]
FROM [Customers] AS [t0]
WHERE EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [Orders] AS [t1]
    WHERE (EXISTS(
        SELECT NULL AS [EMPTY]
        FROM [OrderDetails] AS [t2]
        INNER JOIN [Products] AS [t3] ON [t3].[ProductID] = [t2].[ProductID]
        LEFT OUTER JOIN [Categories] AS [t4] ON [t4].[CategoryID] = [t3].[CategoryID]
        WHERE ([t4].[CategoryName] = @p0) AND ([t2].[OrderID] = [t1].[OrderID])
        )) AND ([t1].[CustomerID] = [t0].[CustomerID])
    )

Note how LINQ generates the JOINs in the SQL for us.  There was no need to explicitly do a join in the LINQ code.  Instead, we used the navigation properties that are created for us (provided your database has foreign keys!).

So the final result was a fairly straightforward LINQ query using method syntax that got translated into some pretty nice SQL (pretty much what I would have written myself).

There are always many ways to write LINQ queries, and I recommend experimenting directly in LINQPad to see what makes the most sense for you.  You’ll find that as you start thinking more in LINQ, as opposed to SQL, that the queries become much simpler.

Hope this helps.

May 27, 2009

LINQPad Graphs

Filed under: .NET,LINQ — Larry Parker @ 1:22 pm

If you’re a LINQ user and haven’t already downloaded LINQPad, get it here.  It’s free, although I highly recommend purchasing a license (for a nominal fee) to get auto-completion support.  I really could have used that feature a couple of years ago when it first came out when I was learning LINQ (but I still find it useful now).

So here’s a nice feature in one of the recent LINQPad releases – LINQPad graphs.  After executing your query, if you click the ≡ symbol on the column header, you will get a nice horizontal bar graph of your data.

I’m actually using this for a quick-and-dirty dashboard to monitor packet load on a web server:

LINQPadGraph

Pretty cool!

September 7, 2007

LINQ is Fantastic!

Filed under: .NET,LINQ,Orcas,technology — Larry Parker @ 2:15 am

I finally got the opportunity to use LINQ in a real project.  Up until a couple of days ago it was always a quick prototype here, install the latest CTP there, read a blog about LINQ, etc.  But there’s nothing like diving in and giving it your best shot on a data-intensive ETL app that would otherwise force you to hand-code a ton of opaque SQL strings using ADO.NET.

For the past two days, I have been sailing along and the code almost seems to be writing itself.  Well not really, but I’m almost done with my app and I have not had to write a single SQL query, and not one INSERT or UPDATE statement.

It was especially nice to see that the SQL generated by LINQ for a moderately complex query was exactly what I expected.  I was a bit concerned that the SQL would be convoluted and unnecessarily use temp tables, but after seeing what got generated I’m getting more confident that I won’t need to worry about it too much.

Perhaps the days of writing explicit SQL will become a thing of the past for me, much like writing assembler code was twenty years ago when I moved to a compiled language and no longer had to worry about the machine code behind the scenes.

Anyway, I hope to post more about LINQ as I continue to get better at it, but my initial test-drive has been extremely positive.  Thank you Microsoft!

July 26, 2007

Orcas Beta 2

Filed under: .NET,LINQ,Orcas,technology,WPF — Larry Parker @ 12:23 am

Looks like Orcas Beta 2 could be available either Thursday or Friday!

http://blogs.zdnet.com/microsoft/?p=594

This is great timing for me since I am just starting the next design and coding cycle of my product.

I’ve been looking forward to using LINQ for a while.  It will be nice to move my SQL out of strings and into an environment where I get strong typing and Intellisense.

 I’m also looking forward to the new WPF designer so I can see what my UI will look like at design time instead of runtime.

Hopefully things will go well with Beta 2, and I’ll post some blogs as I use it.

Create a free website or blog at WordPress.com.