views:

344

answers:

4

I have a website built using Asp.net and LinqToSql for Data Access. In a certain section of the site, LinqToSql produces a query that looks like this (from my dev machine):

select ...
from table1
left outer join table2 on table1 where ...
left outer join table3 on table2 where ...

Since the connection between table2 and table1 is not always there, the left outer join is appropriate in this situation. And since the link between table3 and table1 goes through table2, it also needs a left outer join. This sql returns the correct recordset.

I just put the code up to a server. Running the identical code in the same scenario, LinqToSql produces the following query:

select ...
from table1
left outer join table2 on table1 where ...
join table3 on table2 where ...

For some reason, it renders the join between table2 and table3 as an inner join, instead of an outer join. This results in zero records being returned from the query.

Both dev machine and server are using .Net 3.5 SP1. Dev machine is Vista64, Server is Windows Server 2003 SP2. A colleague of mine using Windows XP PRO also confirmed the same correct behavior on their dev machine.

Can anyone think of a reason why the server would create different sql? How can I fix this? It seems to be something tied into the way that Linq and .Net is running on the server. However, I can't think of any way to confirm and fix this.


Linq Code (I am only including the parts that are relevant to the section where the sql changed):

from Import_Table t in db.Import_Tables
select new {
   CheckedOutUser = (!t.IsCheckedOut) ? "--" : t.Import_CheckoutHistory.System_User.FirstName + " " + t.Import_CheckoutHistory.System_User.LastName,
   CheckedOutUserID = (!t.IsCheckedOut) ? 0 : t.Import_CheckoutHistory.System_UserID};

In the context of the description above, table1 = Import_Table, table2 = Import_CheckoutHistory, table3 = System_User. If I comment out the line here that begins with "CheckedOutUser = ..." then it works on the server - so this is definitely the culprit.

Actual sql returned:

SELECT 
  (CASE WHEN NOT ([t0].[IsCheckedOut] = 1) THEN CONVERT(NVarChar(401),'--') ELSE ([t2].[FirstName] + ' ') + [t2].[LastName] END) AS [CheckedOutUser], 
  (CASE WHEN NOT ([t0].[IsCheckedOut] = 1) THEN 0 ELSE [t1].[system_UserID] END) AS [CheckedOutUserID]
FROM [dbo].[import_Table] AS [t0] 
LEFT OUTER JOIN [dbo].[import_CheckoutHistory] AS [t1] ON [t1].[import_CheckoutHistoryID] = [t0].[import_CheckoutHistoryID] 
LEFT OUTER/INNER JOIN [dbo].[system_User] AS [t2] ON [t2].[system_UserID] = [t1].[system_UserID]

On the dev machines, the last line begins with "Left outer". On the server, the last line begins with "Inner"

Update: My solution is below

A: 

Sounds like the LINQ to SQL classes (DBML and/or associated code generation) between the two is not the same - specifically how the association is defined between these two tables.

DamienG
I thought of that and made sure to copy the dbml files again, just in case they somehow got out of synch. Didn't help. Identical dbml files working off of the same DB.
Yaakov Ellis
+2  A: 

Is your production database different to your development one, e.g. SQL Server 2008 instead of 2005? I believe LINQ to SQL will vary the SQL it generates based on the actual execution-time database it's talking to.

Also, are the schemas exactly the same on both databases?

Jon Skeet
They are both using the same database.
Yaakov Ellis
So unless there are two versions of .Net 3.5 SP1 that I could be using, the only difference between the two that I can tell is the host environment: On Vita or XP with VS 2008 + 3.5 SP1 installed it works, on Windows Server 2003 with .Net 3.5 SP1 installed it doesn't.
Yaakov Ellis
Can you try another WS2K3 box to see whether that really is it?
Jon Skeet
I would expect the inner/outer join difference to be based on LINQ's idea of the constraints, to be honest...
Jon Skeet
There is no OS-specific code in LINQ to SQL. The only thing that affect the query is 1. The query, 2. The database version and 3. The schema.
DamienG
A: 

I have checked the following:

  1. Both use the same database
  2. Both have the identical code
  3. Both have the identical dbml file

I know that something has to be out of synch somewhere, but I can't find it.

So I have implemented the following workaround: I added a view to my database that includes both left outer joins. This view is now in my dbml file, and in the query above, I reference the view instead of the table. This is working fine.

Yaakov Ellis
poor solution imo
Shawn Simon
you have a better suggestion? It is the only thing tried that solved the problem.
Yaakov Ellis
A: 

I have the same issue. Can't figure any difference. I am going to split my query into two and do an union.