DLINQ + Solving the Many to Many problem

A while back, Scott Guthrie posted in the comments, that LINQ didn't support, or had trouble with Many to Many relationships.  I'm not sure if the code-base has changed, or I haven't considered a full scope, but I've managed to get it to work, and it's slick!  I'll jump straight to the magic here. 

I've created a Web Project, and added an SQL Database.  I'm keeping this example simple, so for this example, we have Products, and Categories.  Products can be a member of multiple categories, so lets get started!

I'm using the standard many to many method of using a interim table between the two tables, using a 1 to many on each side.  Here's my LINQ diagram to illustrate:

 

 Untitled-1

 

It's important to note, that for this to work, your interim table MUST have an identity field defined.  In this case I just called it RowID

I've loaded up my tables with some example data to test with, you can create your own, or follow my example.

 

1 Hotdog's
2 Soda
3 Tea
4 Beer
5 Hamburgers
6 Chips
7 Dip
8 Meat Cake

 

1 Food
2 Beverage

 

1 1
2 2
2 3
2 4
1 4
1 5
1 6
1 7
2 8
1 8

 

Ok, from this set of data, we can see that most things only have one category, but both Beer and Meat Cake are both a beverage, and a food!  Right on!  Ok, so now to test the functionality, lets jump into a class

First we need to try a simple select that's meaningful.  In this case, lets select all the products that are beverages, and all the products that are food. :)

Food:

Public Class TestMany
    Public Shared Function Testing()
        Dim db As New ManyToManyDataContext
        Dim query = From p In db.ProductCategories _
                    Where p.Category.CategoryName = "Food" _
                    Select p.Product.ProductName



    End Function
End Class

 

The important thing to note here, is we START at the linking table between the two

Beverage:

Public Class TestMany
    Public Shared Function Testing()
        Dim db As New ManyToManyDataContext
        Dim query = From p In db.ProductCategories _
                    Where p.Category.CategoryName = "Beverage" _
                    Select p.Product.ProductName



    End Function
End Class

 

Now - you're saying, but what if I want the products that are JUST in the food AND beverage category.  Here's where it gets a little tricky, but yes my good friend, it can be done!

Dim db As New ManyToManyDataContext
        Dim prod1 = (From c In db.ProductCategories _
                     Where (c.Category.CategoryName = "Beverage") _
                     Select c.Product.ProductName, c.Category.CategoryName)

        Dim prod2 = (From c In db.ProductCategories _
                     Where (c.Category.CategoryName = "Food") _
                     Select c.Product.ProductName, c.Category.CategoryName)

        Dim result = (From c In prod1 Join d In prod2 On c.CategoryName Equals d.CategoryName _
                      Select c.ProductName)

 

And there you have it.  LINQ's inline ability to query a result set, and JOIN right in code, creates a listing of only products that are in both the food and beverage category. 

Have fun!

Bryan Sampica

3 Comments

  • Have you tried running this with your SQL Profiler running? In yuor final scenario, I think you'll end up executing three SQL queries, not two. I ran into this in a similar situation, and am curious how it would shake out as above.

  • I sure havent. Unfortunatly I work in Visual Basic. Were I to do this in C# I could easily see the query being generated.

    I'll get Query Analyzer loaded up sometime soon and give a crack at the results. I think you're right though, it's going to generate three queries, not two - the good news is it uses connection pooling, and command pooling to stream them together into a single over the wire call to the DB, that returns a single set of results.

    This all happens at the time you try to enumerate over the returned data.

  • As I understand it, LINQ will actually defer query execution until you actually access the data. So if you step through the set of code in the above query, you won't even touch the database.

    You'll need to actually iterate through the data to have the SQL query execute. So, at that point, my guess is that it turns into one query (and as such can be optimized by LINQ or SQL Server).

Comments have been disabled for this content.