Howard Pinsley
Howard Pinsley

Reputation: 11468

Expected the Entity Framework's ObjectQuery(Of T).Include Method to behave differently

I'm not quite understanding why the Include clause on this query

from m in _cmsDb.Matters.Include("MatterContacts.ClientContact.Name")
  where m.CLIENT_CODE == clientCode && m.MATTER_CODE == matterCode
from mc in m.MatterContacts
select mc.ClientContact;

and the subsequent navigation property references made on the resultant ClientContact entities is not satistifed with a single SQL call. The Matter entity has many MatterContact and each one of those links to a single ClientContact and this last entity has a navigation property called Name which links to a Name entity.

When tracing the SQL, I see that my Include clause has caused joins to happen all the way down to the table containting the Name entity. Here is an extraction of the joins I am seeing:

HBM_MATTER INNER JOIN [dbo].[HBA_MATTER_CONT] AS [Extent2] ON [Extent1].[MATTER_UNO] = [Extent2].[MATTER_UNO]
LEFT OUTER JOIN (... FROM [dbo].[HBA_CLIENT_CONT] AS [HBA_CLIENT_CONT]) AS [Extent3] ON [Extent2].[CONTACT_UNO] = [Extent3].[CONTACT_UNO])
FROM [dbo].[HBM_NAME] AS [HBM_NAME]) AS [Extent4] ON [Extent3].[NAME_UNO] = [Extent4].[NAME_UNO]

So I see the joins happening all the way through the hierarchy. However, when I access the properties of the Name entity (e.g. .Name.FirstName), I see additional SQL calls to look up the name.

e.g.

...
FROM (SELECT ...      FROM [dbo].[HBM_NAME] AS [HBM_NAME]) AS [Extent1]
WHERE [Extent1].[NAME_UNO] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=204629

I would have thought that the Include would have brought the Name entity into memory for the returned ClientContact objects. But the trace would indicate otherwise.

Upvotes: 0

Views: 253

Answers (1)

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364249

Common rule of Include is that it works only if you don't use projection or custom join. I think the real rule is: Shape of the query mustn't change. If you use Include on Matter I expect you must also return Matter instances to let the magic do its work. You are using Include on Matter but select ClientContract - the shape of the query has changed.

What happens if you try this:

ObjectQuery<ClientContract> query = (ObjectQuery<ClientContract>)
   (from m in _cmsDb.Matters where m.CLIENT_CODE == clientCode && m.MATTER_CODE == matterCode  
    from mc in m.MatterContacts  
    select mc.ClientContact);

var data = query.Include("Name").ToList();

Upvotes: 1

Related Questions