See below 2 versions of code and SQL it produces. I want to load preferences but I also want to bring only my user preferences and therefore I use WHERE clause. But as soon as I put it in – I don’t get OUTER join anymore. Why?
var query = from p in context.Preferences
join up in context.UserPreferences on p.PreferenceKey equals up.PreferenceKey into outer
from up in outer.DefaultIfEmpty()
select new MobileRESTEntities.UserPreference
{
CreatedOn = (up == null) ? p.CreatedOn : up.CreatedOn,
UpdatedOn = (up == null) ? p.CreatedOn : (up.UpdatedOn ?? up.CreatedOn),
PreferenceId = p.PreferenceId,
Value = (up == null) ? p.ValueDefault : up.Value,
};
With WHERE:
var query = from p in context.Preferences
join up in context.UserPreferences on p.PreferenceKey equals up.PreferenceKey into outer
from up in outer.DefaultIfEmpty()
where up.UserKey.Equals((int)user.ProviderUserKey)
&&
(
(up == null)
||
((up.UpdatedOn > lastSyncOn && up.UpdatedOn != null) || (up.CreatedOn > lastSyncOn))
)
select new MobileRESTEntities.UserPreference
{
CreatedOn = (up == null) ? p.CreatedOn : up.CreatedOn,
UpdatedOn = (up == null) ? p.CreatedOn : (up.UpdatedOn ?? up.CreatedOn),
PreferenceId = p.PreferenceId,
Value = (up == null) ? p.ValueDefault : up.Value,
};
Without WHERE – GOOD
SELECT
[Extent1].[PreferenceKey] AS [PreferenceKey],
CASE WHEN ([Extent2].[UserPreferenceKey] IS NULL) THEN [Extent1].[CreatedOn] ELSE [Extent2].[CreatedOn] END AS [C1],
CASE WHEN ([Extent2].[UserPreferenceKey] IS NULL) THEN [Extent1].[CreatedOn] WHEN ([Extent2].[UpdatedOn] IS NULL) THEN [Extent2].[CreatedOn] ELSE [Extent2].[UpdatedOn] END AS [C2],
[Extent1].[PreferenceId] AS [PreferenceId],
CASE WHEN ([Extent2].[UserPreferenceKey] IS NULL) THEN [Extent1].[ValueDefault] ELSE [Extent2].[Value] END AS [C3]
FROM [dbo].[MBLPreference] AS [Extent1]
LEFT OUTER JOIN [dbo].[MBLUserPreference] AS [Extent2] ON [Extent1].[PreferenceKey] = [Extent2].[PreferenceKey]
With WHERE – BAD – no OUTER JOIN
exec sp_executesql N'SELECT
[Extent1].[PreferenceKey] AS [PreferenceKey],
[Extent2].[CreatedOn] AS [CreatedOn],
CASE WHEN ([Extent2].[UpdatedOn] IS NULL) THEN [Extent2].[CreatedOn] ELSE [Extent2].[UpdatedOn] END AS [C1],
[Extent1].[PreferenceId] AS [PreferenceId],
[Extent2].[Value] AS [Value]
FROM [dbo].[MBLPreference] AS [Extent1]
INNER JOIN [dbo].[MBLUserPreference] AS [Extent2] ON [Extent1].[PreferenceKey] = [Extent2].[PreferenceKey]
WHERE ([Extent2].[UserKey] = @p__linq__0) AND ((1 = 0) OR (([Extent2].[UpdatedOn] > @p__linq__1) AND ([Extent2].[UpdatedOn] IS NOT NULL)) OR ([Extent2].[CreatedOn] > @p__linq__2))',N'@p__linq__0 int,@p__linq__1 datetime2(7),@p__linq__2 datetime2(7)',@p__linq__0=15,@p__linq__1='0001-01-01 00:00:00',@p__linq__2='0001-01-01 00:00:00'
EDIT
Well yes, WHERE Won’t work as is but my SQL should looks something like:
SELECT P.*
FROM dbo.MBLPreference P
LEFT OUTER JOIN dbo.MBLUserPreference UP ON P.PreferenceKey = UP.PreferenceKey
AND UP.UserKey = 8 AND UP.CreatedOn > '1-1-1'
How should I write LINQ to achieve this?
ANSWER
This is what I needed to do (Move conditions onto join itself)
var query = from p in context.Preferences
join up in context.UserPreferences
.Where(x =>
x.UserKey.Equals((int)user.ProviderUserKey)
&&
((x.UpdatedOn > lastSyncOn && x.UpdatedOn != null) || (x.CreatedOn > lastSyncOn))
)
on p.PreferenceKey equals up.PreferenceKey into outer
from up in outer.DefaultIfEmpty()
select new MobileRESTEntities.UserPreference
{
CreatedOn = (up == null) ? p.CreatedOn : up.CreatedOn,
UpdatedOn = (up == null) ? p.CreatedOn : (up.UpdatedOn ?? up.CreatedOn),
PreferenceId = p.PreferenceId,
Value = (up == null) ? p.ValueDefault : up.Value,
};
I’m not sure what you are trying to achieve, but I believe you need to move condition in
whereup :from p in context.Preferences
join up in context.UserPreferences.Where(x=>x.UserKey ==user.ProviderUserKey &&
(// your other conditions)
)
into outer ....