gpt4 book ai didi

c# - 如何使 EntityFramework 关系可查询?

转载 作者:太空狗 更新时间:2023-10-30 01:05:20 25 4
gpt4 key购买 nike

假设我有这些类(class):

public class Car
{
public int CarId { get; set}
public virtual ICollection<Door> Doors { get; set}
}

public class Door
{
public int DoorId { get; set}
public decimal Weight { get; set}
public int CarId { get; set}
}

我想做这样的事情

foreach ( var car in db.Cars )
{
var x = car.Doors.Min(d => d.Weight);
}

正如我在 EFTraceLog 中看到的那样,他做了类似从 Doors 中选择 *,其中 CarId = @...并在应用程序服务器上计算“Min”,而不是在数据库服务器上

我有非常大的汽车和门表,所以这个操作会持续几分钟。但是如果我把代码改成这个

foreach ( var car in db.Cars )
{
var x = db.Doors.Where(d => d.CarId == car.CarId).Min(d => d.Weight);
}

然后是几秒钟。

为什么会有这么大的差异,如何解决?这里的问题是写起来要简单得多

var x = car.Doors.Min(d => d.Weight);

然后

var x = db.Doors.Where(d => d.CarId == car.CarId).Min(d => d.Weight);

更新

我们正在使用 Entity Framework 5.0

更新 2

我试过这些变体,它们很慢

var x = car.Doors.Select(door => door.Weight).Min();
var x = car.Doors.OrderBy(x => x.Weight).Select(x => x.Weight).FirstOrDefault();
var x = car.Doors.OrderBy(x => x.Weight).Select(x => x.Weight).First();
var x = car.Doors.OrderBy(x => x.Weight).FirstOrDefault().Weight;
var x = car.Doors.OrderBy(x => x.Weight).First().Weight;

只有这个快

var x = db.Doors.Where(d => d.CarId == car.CarId).Min(d => d.Weight);

更新 3

最佳查询生成此 sql

declare @p__linq__0 Int32 = cast(N'204' as Int32);

SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
MIN([Extent1].[Weight]) AS [A1]
FROM [dbo].[Doors] AS [Extent1]
WHERE [Extent1].[CarId] = @p__linq__0
) AS [GroupBy1]

最佳答案

Linq to Entities 仅支持 Min 而没有额外的投影。这意味着您当前的 Min 将使用 Linq To Objects 调用(导致您的 Doors 集合具体化 - 因此您在日志中看到生成的 SQL)。

来自 MSDN :

支持:

TSource Min<TSource>(this IQueryable<TSource> source)

不支持:

TResult Min<TSource, TResult>(this IQueryable<TSource> source,Expression<Func<TSource, TResult>> selector)

您可以尝试使用 OrderBySelectFirstOrDefault( 支持)来实现相同的目的结果:

var min = car.Doors.OrderBy(x => x.Weight).Select(x => x.Weight).FirstOrDefault();

更新:

显然 Entity Framework 不支持 Lazy-Load with Projection,这意味着每当您加载引用的实体(Car.Doors 在您的情况下)框架 Lazy -加载所有数据,您无法选择要加载的属性(Weight)。

这就是 2 个调用不同的原因:

// Accessing 'Doors' thru 'Car' means 'Lazy Load'
car.Doors.Select(x => x.Weight).Min();

但是,

// No 'Lazy Load' involved, hence projection is possible
db.Doors.Where(x => x.CarId == carId).Select(x => x.Weight).Min();

您还可以尝试访问 Car.DoorsEager Load Doors:

foreach ( var car in db.Cars.Include(x => x.Doors))
{
var x = car.Doors.Select(x => x.Weight).Min();
}

(根据 Servy 的建议,我使用了 Min 的缩短替代方案)

关于c# - 如何使 EntityFramework 关系可查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19162414/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com