[英]How to perform this EF Core nested date comparison query in SQL
使用.Net Core 2.1和EF Core 2.1.1和SQL Server
我正在嘗試提取Organizations
及其Communications
清單
然后,我想將其限制為最近6個月內未進行任何Communications
的用戶
這是我略過的ViewModels:
public class OrganizationViewModel
{
public Guid Id { get; set; }
public IEnumerable<CommunicationViewModel> CommunicationViewModels { get; set;
}
public class CommunicationViewModel
{
public Guid Id { get; set; }
public DateTime Date { get; set; }
public Guid OrganizationViewModelId { get; set; }
public OrganizationViewModel OrganizationViewModel { get; set; }
}
這是我的查詢:
DateTime sixMonthsAgo = DateTime.Today.AddMonths(-6);
int pageIndex = 1; // Would be passed in
int pageSize = 3;
IQueryable<OrganizationViewModel> query = _context.Organizations
.AsNoTracking()
.Select(organization => new OrganizationViewModel
{
CommunicationViewModels = organization.Communications.Select(communication => new CommunicationViewModel
{
Date = communication.Date
})
.OrderByDescending(communication => communication.Date)
.Take(1)
.ToList()
})
.Where(organization =>
(!searchViewModel.LimitToLastSixMonths ||
organization.CommunicationViewModels.Any(communication => communication.Date <= sixMonthsAgo)));
int totalAmount = await query.CountAsync();
List<OrganizationViewModel> items = await query
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
這樣可以得到預期的結果,但是當我點擊.CountAsync()
和時,可以在日志中看到對每條記錄執行此查詢。 Skip(..).Take(..)
:
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM (
SELECT TOP(1) [comm].[Date]
FROM [Communications] AS [comm]
WHERE @_outer_Id = [comm].[OrganizationId]
ORDER BY [comm].[Date] DESC
) AS [t]
WHERE [t].[Date] <= @__sixMonthsAgo_0)
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
當.CountAsync()
(稍作編輯)時,我也看到這些警告:
Microsoft.EntityFrameworkCore.Query:警告:LINQ表達式
'where (False OrElse {from CommunicationViewModel cvm in {from Communication comm in value(..EntityQueryable'1[..Models.Communication]) orderby [comm].Date desc where ?= (Property([o], "Id") == Property([comm], "OrganizationId")) =? select new CommunicationViewModel() {Date = [comm].Date} => Take(1) => AsQueryable()} where ([cvm].Date <= __sixMonthsAgo_0) select [cvm] => Any()})'
無法翻譯,將在本地進行評估。
Microsoft.EntityFrameworkCore.Query:警告:LINQ表達式'Count()'無法翻譯,將在本地進行評估。
以及調用.Take(..).Skip(..)
時的類似錯誤:
Microsoft.EntityFrameworkCore.Query:警告:LINQ表達式
same as above
無法翻譯,將在本地進行評估。 Microsoft.EntityFrameworkCore.Query:警告:LINQ表達式'Skip(__ p_1)'無法翻譯,將在本地進行評估。
Microsoft.EntityFrameworkCore.Query:警告:LINQ表達式“ Take(__ p_2)”無法翻譯,將在本地進行評估。
當searchViewModel.LimitToLastSixMonths
為false時,不會發生這種情況
關於如何重寫查詢以不對每個記錄在本地執行該查詢的任何建議?
如果您嘗試將Navigation屬性包含在select中,該怎么辦:
IQueryable<OrganizationViewModel> query = _context.Organizations
.Include(o => o.CommunicationViewModels)
...
我想到了!
這是我的新查詢:
DateTime sixMonthsAgo = DateTime.Today.AddMonths(-6);
int pageIndex = 1; // Would be passed in
int pageSize = 3;
IQueryable<OrganizationViewModel> query = _context.Organizations
.AsNoTracking()
.Select(organization => new OrganizationViewModel
{
CommunicationViewModels = organization.Communications.Select(communication =>
new CommunicationViewModel
{
Id = communication.Id,
Date = communication.Date
})
.OrderByDescending(communicationViewModel => communicationViewModel.Date)
.Take(1)
.Where(communicationViewModel => communicationViewModel.Date <= sixMonthsAgo)
.AsQueryable()
})
.Where(organizationViewModel =>
(!searchViewModel.LimitToLastSixMonths || organizationViewModel.CommunicationViewModels.Any()));
int totalAmount = await query.CountAsync();
List<OrganizationViewModel> items = await query
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
現在,當searchViewModel.LimitToLastSizeMonths
為true
時, searchViewModel.LimitToLastSizeMonths
生成這兩個查詢:
SELECT COUNT(*)
FROM [Organizations] AS [organization]
WHERE EXISTS (
SELECT 1
FROM (
SELECT [t].[Id], [t].[Date]
FROM (
SELECT TOP(1) [communication].[Id], [communication].[Date]
FROM [Communications] AS [communication]
WHERE [organization].[Id] = [communication].[OrganizationId]
ORDER BY [communication].[Date] DESC
) AS [t]
WHERE [t].[Date] <= @__sixMonthsAgo_0
) AS [t0])
SELECT [organization].[Id]
FROM [Organizations] AS [organization]
WHERE EXISTS (
SELECT 1
FROM (
SELECT [t].[Id], [t].[Date]
FROM (
SELECT TOP(1) [communication].[Id], [communication].[Date]
FROM [Communications] AS [communication]
WHERE [organization].[Id] = [communication].[OrganizationId]
ORDER BY [communication].[Date] DESC
) AS [t]
WHERE [t].[Date] <= @__sixMonthsAgo_0
) AS [t0])
ORDER BY (SELECT 1)
OFFSET @__p_1 ROWS FETCH NEXT @__p_2 ROWS ONLY
如果沒有.AsQueryable()
它將返回檢查每個記錄並在本地執行計數和滑雪/ .AsQueryable()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.