Troppi outer join in LinqToSql generato SQL
-
09-09-2019 - |
Domanda
Ho una domanda circa un'istruzione SQL generata da una query LINQ2SQL. Ho due tabelle del database (VisibleForDepartmentId
è una chiave esterna):
AssignableObject Department
---------------------- ------------
AssignableObjectId ┌────> DepartmentId
AssignableObjectType │
VisibleForDepartmentId ───┘
E le seguenti informazioni di mappatura (notare che AssignableObject
è astratta):
<Database Name="SO_755661" Class="DataClassesDataContext">
<Table Name="dbo.AssignableObject" Member="AssignableObjects">
<Type Name="AssignableObject" Modifier="Abstract">
<Column Name="AssignableObjectId" Type="System.Int32"
DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true"
IsDbGenerated="true" CanBeNull="false" />
<Column Name="AssignableObjectType" Type="System.String"
DbType="VarChar(50) NOT NULL" CanBeNull="false"
AccessModifier="Private" IsDiscriminator="true"/>
<Column Name="VisibleForDepartmentId" Type="System.Int32"
DbType="Int" CanBeNull="true" />
<Association Name="Department_AssignableObject" Member="VisibleForDepartment"
ThisKey="VisibleForDepartmentId" OtherKey="DepartmentId"
Type="Department" IsForeignKey="true" />
<Type Name="Asset" InheritanceCode="Asset" IsInheritanceDefault="true" />
<Type Name="Role" InheritanceCode="Role" />
</Type>
</Table>
<Table Name="dbo.Department" Member="Departments">
<Type Name="Department">
<Column Name="DepartmentId" Type="System.Int32"
DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true"
IsDbGenerated="true" CanBeNull="false" />
<Column Name="Name" Type="System.String" DbType="VarChar(50) NOT NULL"
CanBeNull="false" />
<Association Name="Department_AssignableObject" Member="AssignableObjects"
ThisKey="DepartmentId" OtherKey="VisibleForDepartmentId"
Type="AssignableObject" />
</Type>
</Table>
</Database>
E il seguente codice:
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Asset>(a => a.VisibleForDepartment);
dataContext.LoadOptions = loadOptions;
var assets = from a in dataContext.Assets
select a;
Ciò si traduce in una query SQL con due identici esterno sinistro join:
SELECT t0.AssignableObjectType, t0.AssignableObjectId, t0.VisibleForDepartmentId,
t2.test, t2.DepartmentId, t2.Name, t4.test AS test2,
t4.DepartmentId AS DepartmentId2, t4.Name AS Name2
FROM dbo.AssignableObject AS t0
LEFT OUTER JOIN (
SELECT 1 AS test, t1.DepartmentId, t1.Name
FROM dbo.Department AS t1
) AS t2 ON t2.DepartmentId = t0.VisibleForDepartmentId
LEFT OUTER JOIN (
SELECT 1 AS test, t3.DepartmentId, t3.Name
FROM dbo.Department AS t3
) AS t4 ON t4.DepartmentId = t0.VisibleForDepartmentId
Perché ci sono due outer join in cui uno sarebbe stato sufficiente?
Cordiali saluti,
Ronald
Soluzione
ho scoperto che cosa provoca questi esterno duplicato si unisce. Si verificano quando una classe persistente viene ereditata da due o più sottoclassi. Per ogni sottoclasse una nuova outer join viene aggiunto l'istruzione SQL generata se si utilizza LoadWith
.
Nel mio esempio, AssignableObject
ha due sottoclassi: Asset
e Role
. Ciò si traduce in due outer join con la tabella Department
. Se posso aggiungere un'altra sottoclasse, join viene aggiunto un terzo esterno.
Non sono sicuro se SQL Server è abbastanza intelligente per capire che l'outer join sono duplicati. Ho postato questo su Microsoft Connect.
Modifica : A quanto pare il mio problema era un duplicato di un altro problema e non verrà risolto nella prossima versione di LINQ2SQL.
Altri suggerimenti
Avete accidentalmente 2 relazioni di chiave esterna definita sulla base di dati tra gli stessi 2 colonne sulle stesse 2 tavoli?
Si potrebbe provare a fare l'esterno sinistro unirsi alla query stessa. Non sono sicuro di ciò che viene generato SQL come non ho il database qui.
var assets = from a in dataContext.Assets
join d in dataContext.Departments on
a.VisibleForDepartmentId equals d.DepartmentId
into temp
from t in temp.DefaultIfEmpty()
select a;
ho creato una query simile a LINQPad utilizzando il suo database di default
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Products>(a => a.Category);
LoadOptions = loadOptions;
var products = from a in Products
select a;
products.Dump();
e ottenere
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[CategoryID], [t2].[test], [t2].[CategoryID] AS [CategoryID2], [t2].[CategoryName]
FROM [Products] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[CategoryID], [t1].[CategoryName]
FROM [Categories] AS [t1]
) AS [t2] ON [t2].[CategoryID] = [t0].[CategoryID]
Un solo outer join viene utilizzato come previsto.