Note that there are some explanatory texts on larger screens.

plurals
  1. POEntity Framework - Inner Join on Foreign Key
    primarykey
    data
    text
    <p>I am using Entity Framework 4.0 (so I can use it with .NET 3.5) and I generated a DAL from an existing database. </p> <p>In the database I have two tables with the following columns (Nothing is allowed to be NULL):</p> <ol> <li>tblWeapon (WeaponId PK, WeaponLabel)</li> <li>tblShot (ShotId PK, WeaponId)</li> </ol> <p>And there's a foreign key on tblShot's WeaponId to tblWeapon.</p> <p>Then the generated entities look something like this:</p> <pre><code>public class Weapon { public int WeaponId { ... } public string WeaponLabel { ...} public EntityCollection Shots { ... } } public class Shot { public int ShotId { ... } public EntityReference WeaponReference { ... } public Weapon Weapon { ... } } </code></pre> <p>In my code I have a ShotFilter and a WeaponFilter classes that contain criteria to filter the individual tables by. Since the filter for the entities is dynamically generated, I would like to spread generation of the queries to the respective filter classes. Each filter would return an <code>IQueryable&lt;T&gt;</code> and they would be joined as needed to achieve the desired results.</p> <p>What I want to do is get all the Shot objects that reference a weapon where the label contains the text <code>0.5</code>.</p> <p>The problem comes when trying to do an inner join on the <code>IQueryable&lt;Shot&gt;</code> to the <code>IQueryable&lt;Weapon&gt;</code> since <code>Shot</code> doesn't contain a <code>WeaponId</code> field (just a <code>WeaponReference</code>). After scouring the web and not finding much of anything, I found a <a href="http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/76503514-cea9-46f1-9aee-14eb5a8ba822" rel="nofollow">forum post</a> where the answer was to just join on the objects themselves. So I tried this and got the results I was expecting:</p> <pre><code>var oWeaponQuery = from w in oDc.Weapons select w; oWeaponQuery = oWeaponQuery.Where(w => w.Label.Contains("0.5")); var oShotQuery = from s in oDc.Shots select s; oShotQuery = oShotQuery.Join(oWeaponQuery, s => s.Weapon, w => w, (s, w) => s); </code></pre> <p>But when I inspected the actual SQL queried using SQL Server Profiler, I saw this awful statement (and vomited a little):</p> <pre><code>SELECT 1 AS [C1], [Extent1].[ShotId] AS [ShotId], [Extent1].[WeaponId] AS [WeaponId] FROM [dbo].[tblShot] AS [Extent1] INNER JOIN [dbo].[tblWeapon] AS [Extent2] ON EXISTS (SELECT cast(1 as bit) AS [C1] FROM ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1] LEFT OUTER JOIN (SELECT [Extent3].[WeaponId] AS [WeaponId] FROM [dbo].[tblWeapon] AS [Extent3] WHERE [Extent1].[WeaponId] = [Extent3].[WeaponId] ) AS [Project1] ON 1 = 1 LEFT OUTER JOIN (SELECT [Extent4].[WeaponId] AS [WeaponId] FROM [dbo].[tblWeapon] AS [Extent4] WHERE [Extent1].[WeaponId] = [Extent4].[WeaponId] ) AS [Project2] ON 1 = 1 WHERE ([Project1].[WeaponId] = [Extent2].[WeaponId]) OR (([Project2].[WeaponId] IS NULL) AND ([Extent2].[WeaponId] IS NULL)) ) WHERE (CAST(CHARINDEX(N'0.5', [Extent2].[Label]) AS int)) > 0</code></pre> <p>So, how would I do this in the correct or at least efficient manner? Or any other suggestions on how to organize my query generation in a dynamic and distributed manner?</p> <p>Thanks!</p> <hr> <h3>Update With More Details</h3> <p>Part of my issue in doing the join is with EF, in the generated entity for <code>Shot</code> there is no <code>WeaponId</code> property. There's just the <code>WeaponReference</code> property that manages it. So in my join, I would expect to be able to use:</p> <pre><code>oShotQuery = oShotQuery.Join(oWeaponQuery, s => s.WeaponId, w => w.WeaponId, (s, w) => s);</code></pre> <p>But that doesn't work due to <code>WeaponId</code> not being a property of <code>Shot</code>.</p> <p>Then I tried this (which again just seems wonky):</p> <pre><code>oShotQuery = oShotQuery.Join(oWeaponQuery, s => s.Weapon.WeaponId, w => w.WeaponId, (s, w) => s);</code></pre> <p>And that does work, and produces fairly concise SQL (with an exception):</p> <pre><code>SELECT 1 AS [C1], [Extent1].[ShotId] AS [ShotId], [Extent1].[WeaponId] AS [WeaponId] FROM [dbo].[tblShot] AS [Extent1] INNER JOIN [dbo].[tblWeapon] AS [Extent2] ON ([Extent1].[WeaponId] = [Extent2].[WeaponId]) OR (([Extent1].[WeaponId] IS NULL) AND ([Extent2].[WeaponId] IS NULL)) WHERE (CAST(CHARINDEX(N'0.5', [Extent2].[Label]) AS int)) > 0</code></pre> <p>And that exception is this: <code>OR (([Extent1].[WeaponId] IS NULL) AND ([Extent2].[WeaponId] IS NULL))</code>. I don't want where they're both <code>NULL</code>, I only want where they're equal.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload