我遇到与Entity Framework 6.1.3中的一对一关系相关的问题。
我有两节课。
public class Package
{
public Guid Id { get; set; }
public string PackageNo { get; set; }
public double SendingCost{ get; set; }
public virtual PackageAppointment PackageAppointment { get; set; }
}
public class PackageAppointment
{
public DateTime Date { get; set; }
public virtual Package Package { get; set; }
}
,PackageAppointment
的地图类是:
public class PackageAppointmentMap
{
public PackageAppointmentMap()
{
Property(x => x.Date).IsRequired();
HasRequired(x => x.Package).WithOptional(x => x.PackageAppointment).Map(x => x.MapKey("PackageId"));
}
}
一切正常。我对这段关系没有任何问题。问题是查询数据库。每次我使用上下文查询数据库中的Package
实体时,SQL Server探查器都会生成类似这样的内容。
LINQ查询:
var data = await Task.Run(() => GenericService.GetAll().Select(x => x.PackageNo));
SQL Server探查器:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PackageNo] AS [PackageNo],
[Extent1].[SendingCost] AS [SendingCost],
[Extent2].[Id] AS [Id1]
FROM
[dbo].[Package] AS [Extent1]
LEFT OUTER JOIN
[dbo].[PackageAppointment] AS [Extent2] ON [Extent1].[Id] = [Extent2].[PackageId]
我使用context.Package...
执行的每个查询都没有从PackageAppointment
(或任何其他一对一关系)检索数据,实体框架生成左外连接。
我的项目中的实际情况是Package实体有5对一关系。由于这个原因,性能非常低。
也许我应该改变关系或其他什么。我真的不知道如何解决这个性能问题。
请告知。
答案 0 :(得分:3)
您可以将Package和PackageAppointment之间的关系更改为:
public PackageAppointmentMap()
{
Property(x => x.Date).IsRequired();
HasOptional(x => x.Package)
.WithOptionalPrincipal(x => x.PackageAppointment)
.Map(x => x.MapKey("PackageAppointmentId"));
}
这将使您的Package表包含FK PackageAppontmentId,并且您的查询将不具有此连接。同时更改与Package.HasRequired(x => x.PackageAppointment)的关系也适用(可能原因见下文)
之后访问包:
var query = dbContext.Packages.ToString();
返回:
SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[PackageNo] AS [PackageNo],
[Extent1].[SendingCost] AS [SendingCost],
[Extent1].[PackageAppointmentId] AS [PackageAppointmentId]
FROM [dbo].[Packages] AS [Extent1]
另一方面,访问PackageAppointmentss:
var anotherQuery = dbContext.PackageAppointments.ToString();
将导致查询:
SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Date] AS [Date],
[Extent2].[Id] AS [Id1]
FROM [dbo].[PackageAppointments] AS [Extent1]
LEFT OUTER JOIN [dbo].[Packages] AS [Extent2] ON ([Extent2].[PackageAppointmentId] IS NOT NULL) AND ([Extent1].[Id] = [Extent2].[PackageAppointmentId])
[编辑]
为什么会这样?
看起来这似乎是为了改变跟踪。
情景:
您的PackageAppointment
具有必需的Package
。这意味着,您的PackageAppointment
表格具有外键PackageId
,因此当您加载PackageAppointment
时,更改跟踪器会获得有关PackageAppointment
的所有信息,以跟踪对实体的所有可能更改,并且可以轻松跟踪更改PackageAppointment.Package
引用 - 即使您没有真正加载PackageAppointment.PackageId
表中的记录,也会在您加载的实体中对Package
进行比较,这与...相关联PackageAppointment
(延迟加载=关闭)。
另一方面,如果您加载Package
,则可以更改属性PackageAppointment
以引用另一个PackageAppointment。但要跟踪此更改,您必须以某种方式获得与此程序包关联的PackageAppointment.Id
。由于Package
表没有从其自身到PackageAppointment
表的外键,因此您必须进行联接以获取与此PackageAppointment.Id
相关联的Package
。换句话说,如果您不进行此加入,则此实体的更改跟踪将无效,并且如果您对其进行任何更改,则会使您加载引用的PackageAppointment
,这可能无效。
要证明这一点,请尝试为此特定查询添加.AsNoTracking()
并检查返回的查询。
所以代码
var trackingQuery = dbContext.PackageAppointments.ToString();
Console.WriteLine("==========================");
Console.WriteLine("Query with Change Tracker enabled");
Console.WriteLine(trackingQuery);
Console.WriteLine("==========================");
Console.WriteLine("\n\n");
var noTrackingQuery = dbContext.PackageAppointments.AsNoTracking().ToString();
Console.WriteLine("==========================");
Console.WriteLine("Query with Change Tracker disabled");
Console.WriteLine(noTrackingQuery);
Console.WriteLine("==========================");
结果如下:
==========================
Query with Change Tracker enabled
SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Date] AS [Date],
[Extent2].[Id] AS [Id1]
FROM [dbo].[PackageAppointments] AS [Extent1]
LEFT OUTER JOIN [dbo].[Packages] AS [Extent2] ON ([Extent2].[PackageAppointmentId] IS NOT NULL) AND ([Extent1].[Id] = [Extent2].[PackageAppointmentId])
==========================
==========================
Query with Change Tracker disabled
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Date] AS [Date]
FROM [dbo].[PackageAppointments] AS [Extent1]
==========================
正如你所看到的,LEFT OUTER JOIN在这里神奇地消失了,这证明这与变更跟踪系统有关。