簡體   English   中英

Select 來自 select... 在實體框架中查詢

[英]Select from select... query in Entity Framework

在執行此存儲庫部分時,在 ASP.NET MVC 項目中:

public IEnumerable<BillOfLading> GetBillOfLadingsByRequestId(int userRequestId)
{
        var res = db.BillOfLadings.Where(x => x.RequestId == userRequestId).OrderBy(y => y.IssueDate).ToList();
        return res.Select(s => new BillOfLading{
            BillOfLadingId = s.BillOfLadingId,
            BillOfLadingStatusId = s.BillOfLadingStatusId,
            ConfirmDate = s.ConfirmDate,
            EmptyWeight = s.EmptyWeight,
            IssueDate = s.IssueDate,
            LoadingDate = s.LoadingDate,
            Portage = s.Portage,
            PrePortage = s.PrePortage,
            RequestId = s.RequestId,
            TotalNumberOfPackages = s.TotalNumberOfPackages,
            TruckId = s.TruckId,
            WithLoadWeight = s.WithLoadWeight
        });
} 

EF 將生成這樣的查詢:

SELECT 
    [Project1].[BillOfLadingId] AS [BillOfLadingId], 
    [Project1].[BillOfLadingStatusId] AS [BillOfLadingStatusId], 
    [Project1].[RequestId] AS [RequestId], 
    [Project1].[TruckId] AS [TruckId], 
    [Project1].[TotalNumberOfPackages] AS [TotalNumberOfPackages], 
    [Project1].[Portage] AS [Portage], 
    [Project1].[PrePortage] AS [PrePortage], 
    [Project1].[IssueDate] AS [IssueDate], 
    [Project1].[EmptyWeight] AS [EmptyWeight], 
    [Project1].[WithLoadWeight] AS [WithLoadWeight], 
    [Project1].[ConfirmDate] AS [ConfirmDate], 
    [Project1].[LoadingDate] AS [LoadingDate]
    FROM ( SELECT 
        [Extent1].[BillOfLadingId] AS [BillOfLadingId], 
        [Extent1].[BillOfLadingStatusId] AS [BillOfLadingStatusId], 
        [Extent1].[RequestId] AS [RequestId], 
        [Extent1].[TruckId] AS [TruckId], 
        [Extent1].[TotalNumberOfPackages] AS [TotalNumberOfPackages], 
        [Extent1].[Portage] AS [Portage], 
        [Extent1].[PrePortage] AS [PrePortage], 
        [Extent1].[IssueDate] AS [IssueDate], 
        [Extent1].[EmptyWeight] AS [EmptyWeight], 
        [Extent1].[WithLoadWeight] AS [WithLoadWeight], 
        [Extent1].[ConfirmDate] AS [ConfirmDate], 
        [Extent1].[LoadingDate] AS [LoadingDate]
        FROM [dbo].[BillOfLadings] AS [Extent1]
        WHERE [Extent1].[RequestId] = @p__linq__0
    )  AS [Project1]
    ORDER BY [Project1].[IssueDate] ASC

如您所見,它使用兩個 select 子句而不是一個。

是否可以讓 EF 像這樣只使用一個select生成查詢?

select [col1],[col2]... 
from [table] 
where ...  

如果是,我該怎么辦? 您的幫助將不勝感激。

此外,如果我在 linq 查詢中的.ToList()之后不使用select ,則 API 會引發異常:

檢測到自參考循環

這可能是因為 model 中的導航屬性...

EF 生成的 SQL 通常沒有任何問題,但在調查性能問題時最好看看它。 通常,這不是 EF 生成的問題,而是表明有一種更有效的方法可以獲取您想要的數據。

例如,在您的情況下,存在一些問題。

如果“BillOfLading”是您的實體 class,您應該避免更新實體 object 的新副本,而是返回一個跟蹤的或未跟蹤的(分離的)實例:

返回分離的實體:

var bills = db.BillOfLadings
    .AsNoTracking()
    .Where(x => x.RequestId == userRequestId)
    .OrderBy(y => y.IssueDate)
    .ToList();
return bills;

返回分離的實體:

var bills = db.BillOfLadings
    .AsNoTracking()
    .Where(x => x.RequestId == userRequestId)
    .OrderBy(y => y.IssueDate)
    .ToList();
return bills;

返回跟蹤的實體:

var bills = db.BillOfLadings
    .Where(x => x.RequestId == userRequestId)
    .OrderBy(y => y.IssueDate)
    .ToList();
return bills;

如果 BillOfLading class 是 ViewModel/DTO 而不是實體:

var bills = db.BillOfLadings
    .Where(x => x.RequestId == userRequestId)
    .OrderBy(y => y.IssueDate)
    .Select(x => new BillOfLading
    {
         // copy values across...
    }).ToList();
return bills;

您的示例的主要問題是,通過在執行Select()之前在實體上使用ToList() ) ,您將這些實體具體化為 memory,然后Select() /w ToList()將完整的第二個副本分配給 memory . 初始集最終將被處置,但您將 memory 要求以及復制數據的處理時間加倍。

如果 BillOfLading class 是您的實體 class 則存在接受可能將該實體與正在保存的另一個實體相關聯或嘗試更新和保存該實體的實體的任何方法將導致插入重復記錄或關於重復記錄的異常PK。 理想情況下,實體應僅在 DbContext 的 scope 內傳遞,讀取或以其他方式跟蹤它們以避免潛在問題。 作為我給出的一般建議,如果需要在 DbContext 的 scope 之外傳輸數據,則應將其投影到 DTO/ViewModel 以優化發送的數據,並避免分離實體與跟蹤實體之間的混淆。 應避免使用新實體來保存數據,並且在清楚代碼可以預期分離實體與跟蹤實體的位置時,需要小心地傳遞分離的實體。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM