【发布时间】:2013-07-23 14:54:35
【问题描述】:
在使用 Linq 2 SQL 在示例应用程序中实现 AdventureWorks 数据库时,我遇到了一个问题,即 Linq 2 SQL 为我的 DBML 中定义的继承映射中的派生类型生成 SQL 语句的方式。
我的 DBML 中有两个实体,Person 和 PersonPhone(一个 Person 到多个 PersonPhone),没有定义任何继承映射(在后面的示例中,Person 将是一个继承基类)。如果我随后运行以下 Linq 语句,我注意到在进行跟踪时会按预期生成以下 SQL:
void Main()
{
this.DeferredLoadingEnabled = false;
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Person>(n => n.PersonPhones);
this.LoadOptions = dlo;
Person person = this.Persons.SingleOrDefault(n => n.BusinessEntityID == 291);
person.PersonPhones.Dump();
}
DECLARE @p0 Int = 291
SELECT [t0].[BusinessEntityID], [t0].[PersonType], [t0].[NameStyle], [t0].[Title], [t0].[FirstName], [t0].[MiddleName], [t0].[LastName], [t0].[Suffix], [t0].[EmailPromotion], [t0].[AdditionalContactInfo], [t0].[Demographics], [t0].[rowguid], [t0].[ModifiedDate], [t1].[BusinessEntityID] AS [BusinessEntityID2], [t1].[PhoneNumber], [t1].[PhoneNumberTypeID], [t1].[ModifiedDate] AS [ModifiedDate2], (
SELECT COUNT(*)
FROM [Person].[PersonPhone] AS [t2]
WHERE [t2].[BusinessEntityID] = [t0].[BusinessEntityID]
) AS [value]
FROM [Person].[Person] AS [t0]
LEFT OUTER JOIN [Person].[PersonPhone] AS [t1] ON [t1].[BusinessEntityID] = [t0].[BusinessEntityID]
WHERE [t0].[BusinessEntityID] = @p0
ORDER BY [t0].[BusinessEntityID], [t1].[PhoneNumber], [t1].[PhoneNumberTypeID]
结果是在单个语句中生成 SQL。请忽略这可能是低效 SQL 的事实,我要说的是它在单个语句中运行。
但是,如果我在我的 DBML 中包含继承映射信息并定义一个名为 StoreContact(从 Person 派生)的新实体类型并运行完全相同的查询,我实际上会得到不同的结果,如下所示。其中实际上运行了两条 SQL 语句。
DECLARE @p0 Int = 291
SELECT [t0].[PersonType], [t0].[BusinessEntityID], [t0].[NameStyle], [t0].[Title], [t0].[FirstName], [t0].[MiddleName], [t0].[LastName], [t0].[Suffix], [t0].[EmailPromotion], [t0].[AdditionalContactInfo], [t0].[Demographics], [t0].[rowguid], [t0].[ModifiedDate]
FROM [Person].[Person] AS [t0]
WHERE [t0].[BusinessEntityID] = @p0
GO
DECLARE @x1 Int = 291
SELECT [t0].[BusinessEntityID], [t0].[PhoneNumber], [t0].[PhoneNumberTypeID], [t0].[ModifiedDate]
FROM [Person].[PersonPhone] AS [t0]
WHERE [t0].[BusinessEntityID] = @x1
这有点问题,因为这将大大降低我们的应用程序的速度,因为在实现继承功能的情况下,Linq 2 SQL 需要对数据库进行重复调用。看起来拥有 OOP 模型是有代价的。
是否有解决此问题的解决方法以使 SQL 在单个语句中运行?
【问题讨论】:
-
我要表达的一点是,在此示例中,我在继承映射更改之前和之后都使用了 SAME linq 语句。
-
为什么第一个 SQL 做计数? L2S 是插入这个可怕的聚合还是来自您的代码?
-
因为在执行以下行之前不会对数据库运行“查询”:ac.PersonPhones.Count.Dump(),因此它会将其转换为基于 linq 的最合适的 SQL 语句陈述。这只是它在单个 SQL 语句中执行 linq 查询时的一个示例,在该语句中我试图通过继承来实现,它可能生成低效 SQL 的事实并不重要,因为我可以重写我的 Linq 查询为了更有效地进行计数。
-
ac.PersonPhones是不是Iqueryable。 LINQ 不会以任何方式对此进行优化。该语句不可能影响query的执行。现在我怀疑显示的代码是否对应于显示的 SQL。你能回顾一下吗?也许单步执行并观察哪些行生成了哪些 SQL。 -
我已经仔细检查并确认示例中提供的 Linq 代码生成了所述 SQL 语句。我已经通过使用 LinqPad 检查了这一点,它详细说明了执行的 SQL 查询和 SQL Server Profiler。示例中生成的 SQL 是有道理的,根据我编写的 linq 查询,我不会期望有任何不同。
标签: sql linq inheritance linq-to-sql