Note that there are some explanatory texts on larger screens.

plurals
  1. POAssociated tables being fully parsed when referred to with an 'Include' statement using Entity Framework
    primarykey
    data
    text
    <p>I'm having problems with Includes when pulling data out of the entity framework. I posted a very similar question yesterday <a href="https://stackoverflow.com/questions/11727534">here</a>, which has the same sample I'm about to use. I'm using Entity Framework v4.0.</p> <p>I have the following simple model, a table containing list of Page Forms (~200). Each form has one or more Fields (~4000 total), and each field has may have some Parameters (~16000 total).</p> <p><img src="https://i.stack.imgur.com/jCw1H.png" alt="Entity model"></p> <p>I use the following code to pull data out:</p> <pre><code>EntityConnection myConnection = new EntityConnection("name=myModel"); if(conn.State != ConnectionState.Open) { conn.Open(); } ObjectContext context = new ObjectContext("name=myModel"); context.ContextOptions.LazyLoadingEnabled = false; ObjectQuery&lt;PageForm&gt; myObjectSet = context.CreateObjectSet&lt;PageForm&gt;() .Include("FormFields.FormFieldParameters"); IQueryable&lt;PageForm&gt; myFilteredObjectSet = myObjectSet.Where(c =&gt; c.FormID == 1); List&lt;PageForm&gt; myReturnValue = myFilteredObjectSet.toList(); </code></pre> <p>Which generates the following sql query</p> <pre><code>SELECT [Project1].[FormID] AS [FormID], [Project1].[FormName] AS [FormName], [Project1].[C2] AS [C1], [Project1].[FormID1] AS [FormID1], [Project1].[FieldID] AS [FieldID], [Project1].[FieldName] AS [FieldName], [Project1].[C1] AS [C2], [Project1].[FieldParamID] AS [FieldParamID], [Project1].[Value] AS [Value], [Project1].[FieldID1] AS [FieldID1] FROM ( SELECT [Extent1].[FormID] AS [FormID], [Extent1].[FormName] AS [FormName], [Join1].[FieldID] AS [FieldID], [Join1].[FieldName] AS [FieldName], [Join1].[FormID] AS [FormID1], [Join1].[FieldParamID] AS [FieldParamID], [Join1].[Value] AS [Value], [Join1].[FieldID1] AS [FieldID1], CASE WHEN ([Join1].[FieldID] IS NULL) THEN CAST(NULL AS int) WHEN ([Join1].[FieldParamID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1], CASE WHEN ([Join1].[FieldID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] FROM [dbo].[PageForm] AS [Extent1] LEFT OUTER JOIN ( SELECT [Extent2].[FieldID] AS [FieldID], [Extent2].[FieldName] AS [FieldName], [Extent2].[FormID] AS [FormID], [Extent3].[FieldParamID] AS [FieldParamID], [Extent3].[Value] AS [Value], [Extent3].[FieldID] AS [FieldID1] FROM [dbo].[FormField] AS [Extent2] LEFT OUTER JOIN [dbo].[FormFieldParameter] AS [Extent3] ON [Extent2].[FieldID] = [Extent3].[FieldID] ) AS [Join1] ON [Extent1].[FormID] = [Join1].[FormID] WHERE 1 = [Extent1].[FormID] ) AS [Project1] ORDER BY [Project1].[FormID] ASC, [Project1].[C2] ASC, [Project1].[FieldID] ASC, [Project1].[C1] ASC </code></pre> <p>Now I'm interested in this part of the query:</p> <pre><code>LEFT OUTER JOIN ( SELECT /**/ FROM [dbo].[FormField] AS [Extent2] LEFT OUTER JOIN [dbo].[FormFieldParameter] AS [Extent3] ON [Extent2].[FieldID] = [Extent3].[FieldID] ) AS [Join1] ON [Extent1].[FormID] = [Join1].[FormID] </code></pre> <p>This seems to query the entire FormField and FormFieldParameter tables, with no filtering applied. So, what I think is happening, is that using <code>.Include("FormField.FormFieldParameter")</code> is akin to saying - "And return all data from these tables in the resulting query". What I really want is "Return only the data from these tables which relates to the filtered PageForm table".</p> <p>Is there a way to do this? Sorry if this question sounds too simple, or similar to my previous question, but I'm really having trouble getting my head around the internals of Entity Framework.</p> <p>EDIT 1:</p> <p>If I change the above sample to the following which includes a where clause, then the query is orders of magnitude faster (roughly 10x faster).</p> <pre><code>LEFT OUTER JOIN ( SELECT /**/ FROM [dbo].[FormField] AS [Extent2] LEFT OUTER JOIN [dbo].[FormFieldParameter] AS [Extent3] ON [Extent2].[FieldID] = [Extent3].[FieldID] WHERE 1 = [Extent2].[FormID] ) AS [Join1] ON [Extent1].[FormID] = [Join1].[FormID] </code></pre> <p>EDIT 2: </p> <p>Some more information. I've figured out that If i add some funky filtering to the initial query, I can force a much more efficient query to be ran.</p> <pre><code>IQueryable&lt;PageForm&gt; myFilteredObjectSet = myObjectSet .Where(c =&gt; c.FormID == 1) .Where(a =&gt; a.FormFields .Where(c =&gt; c.FormFieldParameters .Any(d =&gt; d.FieldID == c.FieldID)) .Any(b =&gt; b.FormID == 1) ); </code></pre> <p>This causes the query to filter correctly, and runs much faster. However, I'm certain this isn't the best way go about this, as the nested Where/Any statements very quickly become a nightmare to deal with when you have more than a handful of Includes. There must be a better way?</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