Projecting into an unmapped property from a LINQ to SQL query

On page 216 of LINQ in Action, I made a comment that unmapped properties in a mapped class cannot be used in a LINQ to SQL projection. This was true with the beta bits, but only partially true with the release bits. To begin, let's consider the Author table we have in the book samples.

The Author class has separate fields for the first and last name. Each of these is mapped to the corresponding fields in the Author table. In the book, we show how you can create a read only property in a partial class (so that it won't get clobbered when we regenerate our classes in the designer). The new property is trivial:

   Partial Public Class Author
        Public ReadOnly Property FormattedName() As String
            Get
                Return Me.FirstName & " " & Me.LastName
            End Get
        End Property
    End Class

Notice here that there are no mapping attributes to this property. In part, that is because there is no corresponding field in the table. As we show in the book, you are free to query the author table and return Author objects. From there, you can display the FormattedName as follows:

           Dim authors = From a In context.Authors _
                          Select a
            For Each a In authors
                Console.WriteLine(a.FormattedName & "; " & a.WebSite)
            Next

This works fine because we are projecting the complete Author type. However, in early builds, we couldn't project the unmapped properties into an anonymous type like this:

            Dim authors = From a In context.Authors _
                          Select a.FormattedName, a.WebSite

If you tried to use this projection, you would get a runtime exception. In the RTM bits, the behavior was modified. Now, if you try to run the above query (sample 8.25 in the book samples for anyone following along). You will see that the query succeeds and the anonymous type is used. So how can they know how to populate the FormattedName when it is not mapped and doesn't exist in the table itself? No, the provider doesn't look inside the property, determine the mapped properties that are used, and fetch them. While that could work in our simple example, many unmapped properties  would use significantly more resources, many of which may not be members of our class, or methods without direct translation in TSQL. If you look at the generated SQL that is issued when the query is consumed, you might be able to figure out what is happening in this case.

SELECT [t0].[ID], [t0].[LastName], [t0].[FirstName], [t0].[WebSite], [t0].[TimeStamp]
FROM [dbo].[Author] AS [t0]

Notice here, our select clause to the database is not optimized to only return the fields we requested. Instead, all of the fields are returned. So what's going on? They discovered in evaluating the Select clause that there were unmapped properties. At that point, they just turned around and populated a full author object. Using this object, the provider turns around and generates the anonymous type from the object rather than directly from the underlying data store directly. It's a bit of smoke and mirrors at this point.

So the question that came up asks if the next printing of the book needs to be adjusted to remove the statement that you can't project an unmapped property. While you can indeed project these properties, you can't use them elsewhere in the query. Thus if you wanted to sort the data based on the unmapped property, the exception would be thrown. Consider the following query./p>

            Dim authors = From a In context.Authors _
                          Order By a.FormattedName _
                          Select  a.FormattedName, a.WebSite

In this case when we try to run it, we get the following error:

"System.NotSupportedException: The member 'LinqInAction.LinqBooks.Common.VB.SampleClasses.Ch8.Author.FormattedName' has no supported translation to SQL."

Because of this, I plan to leave the note in the chapter warning you of using the unmapped property in your query. Unfortunately, I don't have enough space in the book to insert this complete explanation at this time. I hope this explanation helps some of you who are confused at this point.

Posted on 5/8/2008 6:25:00 PM - Comments (0)
Categories: VB Dev Center , LINQ , VB

Geek Speak resources for the LINQ Migration session

I had a blast on the Geek Speak today. If you missed it, they will have it available on demand from their blog at http://blogs.msdn.com/geekspeak/. It is also live on Channel9. You can even subscribe to the audio feed using your the Zune podcasting functionality from their rss feed. One of the things I love about these events is the variety of the questions that attendees bring.

As I mentioned, the slide deck I used for the session is available in the Files section here as Linq Migration Strategies.

Below are some of the questions that came up and some links to back up my answer for your reading edification.

Q: How do you import schema into VB at the top of the file, if schema is in project it will give you intellisense?

Beth Massi and Avner Aharoni demonstrate this in the webcast available at http://blogs.msdn.com/bethmassi/archive/2008/01/18/channel-9-interview-xml-properties-and-enabling-intellisense.aspx. They also demonstrate generating the schema from a sample XML document.

Q: How would you replace an existing data layer with LINQ to SQL?

I started showing how to take the Personal Web Starter Kit and begin to LINQ enable it. The completed project is available at http://code.msdn.microsoft.com/LinqPersonalWeb.

Q: How does LINQ perform as compared to the other alternatives?

Any time you add a level of indirection there will be some performance penalty. With LINQ to Objects, they basically leverage the iterator pattern the same way the C# 2.0 Yield method works. For LINQ to SQL, the best series on performance is from Rico Mariani starting with http://blogs.msdn.com/ricom/archive/2007/06/22/dlinq-linq-to-sql-performance-part-1.aspx

Q: Where can we find patterns and practices guidance on LINQ

This post is more along the lines of the Framework Design Guidelines book, but it is good information anyway: http://blogs.msdn.com/mirceat/archive/2008/03/13/linq-framework-design-guidelines.aspx

There is also a Live from Redmond VB9 webcast discussing best practices at http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032337466

Additional "How do I" videos are available at  http://msdn2.microsoft.com/en-us/vbasic/bb466226.aspx

Q: What advice do you have for passing data across tiers? If we can’t pass context across tiers, can we pass resultant objects?

There isn't really a single difinitive post on this one. Searching for "DataContext" and "Short lived" or "Unit of work" should supply a number of examples, including the following:

http://msdn2.microsoft.com/en-us/library/system.data.linq.datacontext.aspx

This forum post includes responses by Keith Farmer and Matt Warren who were both intimately involved with creating LINQ to SQL: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2485909&SiteID=1. Matt states, "You'll most often want a new context for every interesting unit of work.  DataContext's should be short lived if they can be. The only scenario where you'd keep a DataContext around for a long time would be if you were bulding the equivalent of a 2-tier UI based data-entry/editting appliction."

Dino Esposito notes: http://weblogs.asp.net/despos/archive/2008/03/19/more-on-datacontext-in-hopefully-a-realistic-world.aspx

Some additional resources mentioned:

Rick Strahl: http://www.west-wind.com/weblog/default.aspx

Beth Massi: http://blogs.msdn.com/bethmassi/

MSDN LINQ forum: http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=123&SiteID=1

Q: Regarding Linq to Entities, I hear that the entities will not use the same change tracking model to permit emitting across tiers, by making the EntitySets serializable and have the changes tracked on a set by set basis, can you confirm deny? Info on this?

I don't know enough to comment on this. I would recommend asking the question on the ADO.NET Entity Framework forum at http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=533&SiteID=1.

Posted on 4/2/2008 8:40:00 PM - Comments (0)
Categories: LINQ

Geek Speak discusses LINQ Migration Strategies

Tomorrow, Wednesday 4/2/2008, I will be the guest speaker on the Geek Speak webcast. We will be discussing strategies for beginning to incorporate LINQ into your existing application infrastructure. In many cases, that does not mean replacing your entire data stack, but rather using pieces of LINQ to add functionality and in new components. Please join us. The Geek Speak webcasts are often driven by attendee questions. The more questions, the better the event.

When: Wednesday, April 02, 2008 12:00 -1:00 PM (GMT-08:00) Pacific Time (US & Canada) or 3:00 - 4:00 PM Eastern Time.
Where: Live Meeting
Registration URL:
Posted on 4/1/2008 6:35:00 AM - Comments (0)
Categories: LINQ

Joining composite keys with LINQ

LINQ makes working with data in its various guises easier. By intergating it into the language, we have rich integrated support for working with data. However, there are times where the syntax is slighly different from what you would typically expect with TSQL. Once case where this occurs is when trying to join two data sources that are related by more than one field (also know as a composite key). This differs from standard joins where one table has a primary key and the other table has a foreign key id. Here's a sample table structure for a standard join in Northwind between the Products and Categories:

With Linq, this join could be represented with the following query:

Dim query = _
     From p In dc.Products _
     Join c In dc.Categories _
     On p.CategoryID Equals c.CategoryID _
     Select p.ProductName, c.CategoryName

So far, there's not much new in this query. Here, "p" is the outer variable and "c" is the inner variable of the join. Likewise, p.CategoryID is the outerKeySelector and c.CategoryID is the InnerKeySelector in the Join extension method.

This works fine when we have single values that can be compared easily. However, how can we specify multiple fields for the KeySelectors on the join? In my work with reverse mortgages, we have a situation where the loan amount is based in part on the lending limits set forth by HUD. In their limits, they specify the State and County for each limit. In this case, I need to join those values against the loan property's state and county to come up with the limit amount. Let's consider the following partial table schemas.

In this case, we could join the tables in TSQL with the following query:

SELECT LendingLimits.Amount
FROM LendingLimits
INNER JOIN Property
ON LendingLimits.State=Property.State AND
      LendingLimits.County=Property.County
WHERE PropertyId=@SearchValue  AND
      EffectiveDate = @TargetDate

Unfortunately, the Join extension method does not support the ability to provide the InnerKeySelector/OuterKeySelector as a series of expressions. However, when dealing with objects, we can compare objects to see if they equal each other. Therefore, the solution in this case is to join two anonymous types and compare them against each other. Here's the corresponding LINQ query. Notice the difference in the On clause. If you understand working with objects, this syntax should make sense.

Dim query1 = _
    From l In dc.LendingLimits _
    Join p In dc.Properties _
    On New With {l.County, l.State} Equals _
          New With {p.County, p.State} _
    Where p.PropertyId = SearchValue And _
          l.EffectiveDate = TargetDate _
    Select l.Amount

Posted on 3/18/2008 12:48:00 AM - Comments (1)
Categories: VB Dev Center , LINQ , VB

LINQ enabled Personal Web Starter Kit in C#

I love it when projects take a life of their own. A while back, I posted my LINQ enabled  Personal Web Starter Kit in VB and received several requests to provide a C# port. Thankfully, one brave soul stepped up and did the port for me. Thanks go to Stephen Murray for undertaking the challenge. As is often the case, one of the best ways to learn a technology is to use it.

If you're interested in this sample, you can check out the project at the MSDN code center. Specifically, you can access the original VB version or Stephen's C# Port. As always, let us know what you Thinq.

Posted on 3/9/2008 9:36:00 PM - Comments (0)
Categories: C# , LINQ

    Next