LINQtoSQL 生成的 SQL 中外连接过多

发布于 2024-07-16 22:04:31 字数 3055 浏览 10 评论 0原文

我对 LINQ2SQL 查询生成的 SQL 语句有疑问。 我有两个数据库表(VisibleForDepartmentId 是外键):

AssignableObject                 Department
----------------------           ------------
AssignableObjectId        ┌────> DepartmentId
AssignableObjectType      │
VisibleForDepartmentId ───┘

以及以下映射信息(请注意,AssignableObject 是抽象的):

<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>

以及以下代码:

var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Asset>(a => a.VisibleForDepartment);
dataContext.LoadOptions = loadOptions;
var assets = from a in dataContext.Assets
             select a;

这会生成 SQL具有两个相同的左外连接的查询:

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

为什么有两个外连接,而一个就足够了?

亲切的问候,

罗纳德

I have a question about a SQL statement generated by a LINQ2SQL query. I have two database tables (VisibleForDepartmentId is a foreign key):

AssignableObject                 Department
----------------------           ------------
AssignableObjectId        ┌────> DepartmentId
AssignableObjectType      │
VisibleForDepartmentId ───┘

And the following mapping information (note that AssignableObject is abstract):

<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>

And the following code:

var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Asset>(a => a.VisibleForDepartment);
dataContext.LoadOptions = loadOptions;
var assets = from a in dataContext.Assets
             select a;

This results in a SQL query with two identical left outer joins:

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

Why are there two outer joins where one would have been sufficient?

Kind regards,

Ronald

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北恋 2024-07-23 22:04:31

我找出了导致这些重复的外连接的原因。 当持久类被两个或多个子类继承时,就会发生这种情况。 对于每个子类,如果使用 LoadWith,则会将新的外部联接添加到生成的 SQL 语句中。

在我的示例中,AssignableObject 有两个子类:AssetRole。 这会产生与 Department 表的两个外部联接。 如果我添加另一个子类,则会添加第三个外部联接。

我不确定 SQL Server 是否足够聪明,能够意识到外连接是重复的。 我已在 Microsoft Connect 上发布此内容

编辑:显然我的问题是的重复另一个问题,并且不会在 LINQ2SQL 的下一版本中修复。

I found out what causes these duplicated outer joins. They occur when a persistent class is inherited by two or more subclasses. For each subclass a new outer join is added to the generated SQL statement if you use LoadWith.

In my example, AssignableObject has two subclasses: Asset and Role. This results in two outer joins with the Department table. If I add another subclass, a third outer join is added.

I'm not sure whether SQL Server is smart enough to realize that the outer joins are duplicated. I've posted this on Microsoft Connect.

EDIT: Apparently my issue was a duplicate of another issue and it won't be fixed in the next release of LINQ2SQL.

夏至、离别 2024-07-23 22:04:31

您是否意外地在数据库中定义了 2 个外键关系
相同的 2 个表上的相同 2 列?

Do you accidentally have 2 foreign key relationships defined on your database between
the same 2 columns on the same 2 tables ?

但可醉心 2024-07-23 22:04:31

您可以尝试在查询本身中进行左外连接。 我不确定生成了什么 SQL,因为我这里没有你的数据库。

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;

You could try doing the left outer join in the query itself. I'm not sure what SQL is generated as I don't have your database here.

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;
终止放荡 2024-07-23 22:04:31

我使用其默认数据库在 LINQPad 中创建了一个类似的查询,

var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Products>(a => a.Category);
LoadOptions = loadOptions;

var products = from a in Products
               select a;

products.Dump();

并按预期得到

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]

Only one OUTER JOIN is use 。

I have created a similar query in LINQPad using its default database

var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Products>(a => a.Category);
LoadOptions = loadOptions;

var products = from a in Products
               select a;

products.Dump();

and get

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]

Only one OUTER JOIN is used as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文