Blog
LINQ Likes Foreign Keys
11/16/09
When developing applications, you’ll probably use LINQ mostly for accessing SQL/Server databases. LINQ to SQL provides an IntelliSense-friendly technique for writing database queries, and can return your data in an object hierarchy that models your application’s real world domain.
This graceful nesting of objects within objects is yours if, and only if, you’ve added foreign key relationships to the tables in your database.
To avoid confusion (and disappointment) let’s be precise: it’s not enough to have a field in one table that you can associate with a key in another. You need to actually create the foreign key relationship. SQL/Server Management Studio gives you a way to do that declaratively; or if you prefer, you can create the keys using T-SQL. One way or the other, you want to make sure they’re in place.
Can you write LINQ queries without the foreign keys being there? Yes, but you then take on the responsibility of drilling down your object hierarchy to get related objects. If you’ve taken the time to add the foreign keys, LINQ will do all the heavy lifting for you.
Let’s look at an example to see the difference foreign keys make.
The schema for our example is pretty straightforward:
• a Customer table holds a row for each customer, and has a primary key of CustomerID
• an Order table holds a row for each order, has a primary key of OrderID, and has a CustomerID field for the customer that placed the order
• an Item table holds a row for each item in an order, has a primary key of ItemID, and has an OrderID field for the order that contains the item.
For our first variation, we put no foreign keys on the tables.
Our goal is to produce a list of customers, their orders, and the items contained in the orders. The code to do that would look like this:
// First, get the customers
IEnumerable<Customer2> customers = from c in dc.Customer2s
select c;
foreach (Customer2 c in customers)
{
Console.WriteLine(String.Format("Invoice for {0}", c.Name));
// For each customer, get the order.
IEnumerable<Order2> orders = from o in dc.Order2s
where o.Customer2ID == c.Customer2ID
select o;
foreach (Order2 o in orders)
{
Console.WriteLine(String.Format("- Order Date {0:d}", o.OrderDate));
IEnumerable<Item2> items = from i in dc.Item2s
where i.Order2ID == o.Order2ID
select i;
foreach (Item2 i in items)
Console.WriteLine(String.Format(" *** Item: {0}, Price {1}", i.Description, i.Price));
}
}
In this code block, we’ve queried for the customers; iterated through that list, and executed a second query for the orders; iterated through the orders list and executed a third query for the items. With a long list of customers and orders, that could be a lot of queries.
Now, you could have LINQ join the tables, and then iterate through the results building your own hierarchy of objects. This would require defining classes for your objects, a more complicated LINQ query, and then the code to populate the objects and nest them. I’ll leave that to the reader.
For the second variation, we tie the tables together with foreign keys. Aside from the benefits we get from referential integrity, we have a substantially smaller code block:
// First, get the customers
IEnumerable<Customer1> Lcustomers = from c in dc.Customer1s
select c;
foreach (Customer1 c in Lcustomers)
{
Console.WriteLine(String.Format("Invoice for {0}", c.Name));
foreach (Order1 o in c.Order1s)
{
Console.WriteLine(String.Format("- Order Date {0:d}", o.OrderDate));
foreach (Item1 i in o.Item1s)
Console.WriteLine(String.Format(" *** Item: {0}, Price {1}", i.Description,
i.Price));
}
}
To do the same job, we now use only one query, and have much less code. And, notice how the object hierarchy and dot notation make it easy to get to data in any object. Want an item’s price? customer.order.item.Price, and IntelliSense helps you all the way down.
Running these two bits of code produced identical results. Here’s a sample:
Invoices without Foreign Keys
Invoice for Fudd, Elmer
- Order Date 5/1/2009
*** Item: TV, Price 3500.0000
*** Item: TV Stand, Price 89.9500
---------------------------------------------
Invoice for Duck, Daffy
- Order Date 4/1/2009
*** Item: Shoes, Price 49.9500
*** Item: Purse, Price 79.9500
---------------------------------------------
- Order Date 5/4/2009
*** Item: Blouse, Price 24.9500
---------------------------------------------
Invoices without Foreign Keys
Invoice for Fudd, Elmer
- Order Date 5/1/2009
*** Item: TV, Price 3500.0000
*** Item: TV Stand, Price 89.9500
---------------------------------------------
Invoice for Duck, Daffy
- Order Date 4/1/2009
*** Item: Shoes, Price 49.9500
*** Item: Purse, Price 79.9500
---------------------------------------------
- Order Date 5/4/2009
*** Item: Blouse, Price 24.9500
---------------------------------------------
If the benefits of referential integrity haven’t been enough to persuade you to use foreign keys when building your database, consider the benefits you get in your LINQ queries. Less code, fewer database calls, and the data comes back in a hierarchy that matches the real world situation. Key it up!
- Ben Furino, .NET Programming Manager
More Blog Articles
- Outsource Services to Support Business Growth - 08/31/10
- 3 Easy Changes for a Sticky Website -- Web Site Redesign Tips - 08/25/10
- Hiring writers: 5 quick ways to avoid headaches and lawsuits - 08/06/10
- Web traffic: 3 ways to attract customers to your website - 07/23/10
- How do you know if a small business web designer is up to the job? - 07/15/10
- 5 keys to choosing a reputable SEO firm - 06/11/10
- 5 Ways an iPhone App Developer Can Make Your Business Money - 05/25/10
- How is Your Web Strategy? - 03/05/10
- Patience is The Key to Web Success - 03/05/10
- The Website ROI Factor - 02/28/10
- Live Support Chat Software - 02/26/10
- Automate Your Workforce with iPhone - 02/25/10
- Mobile CRM - 02/23/10
- Wordpress for iPhone - 02/22/10
- Mobile Development - 02/19/10
- Coordinates Using the iPhone Simulator - 12/30/09
- Social Media - 12/24/09
- LINQ Likes Foreign Keys - 11/16/09
- Adding a Flickr Slide Show to Your Website - 10/07/09
- Adding a Twitter Feed to Your Site - 09/22/09
- Making Sure Your Website Is Browser Friendly - 09/11/09
- Adding your Facebook Fan Box to Your Website - 08/13/09
- Whats the big deal about BING? - 07/31/09
- Web Design Radio Interview pt 4 - 06/25/09
- Adding a Start Date and End Date to your WordPress Posts - 06/16/09
- Web Design Radio Interview pt 3 - 05/15/09
- Web Design Radio Interview pt 2 - 05/08/09
- Web Design Radio Interview pt 1 - 05/07/09
- Radio Interview - 05/04/09
- Is it Time to Add a Survey Tool to Your Website? - 04/29/09
- Key Step in Building a Website - 04/16/09
- Google Analytics Now Offers iPhone Tracking on Your Website Analytics. - 04/15/09
- Google Video to Discontinue Upload Service - 04/03/09
- LINQ to Objects - 04/01/09
- Sales in a Down Economy - 03/31/09
- Integrating The Facebook Connect Platform Into Your Website - 03/27/09
- Is it Time to Make Sure Your Website is Formatted for Higher Resolution Monitors? - 03/24/09
- Another Reason Reviewing Google Analytics Data is Important. - 03/20/09
- Client-side Reports Using the Report Viewer - 03/18/09
- Targeting the Right Destination in a Hyperlink - 03/17/09
- Is Your Website Multilingual? Should It Be? - 03/12/09
- How to Use Javascript Effectively Without Hurting Your Web Site Search Engine Optimization - 03/05/09
- Top 7 Myths of Web Development - 03/04/09
- Using LINQ - 03/02/09
- Facebook as a Business Tool - 02/27/09
- Proper Keyword Selection for SEO - 02/24/09
- My brother knows a guy who knows a guy who does websites for $500. - 02/23/09
- Maintaining High Touch in a High Tech World - 02/19/09
- Search Engine Optimization And W3C Compliant Web Pages - 02/18/09
- Reach potential clients through RSS - Part 2 - 02/18/09
- Reach potential clients through RSS - Part 1 - 02/17/09
