我一直在尝试重构这个查询一段时间而没有任何运气:
db.Kiosks.Where(kiosk => db.KioskDesignations.Where(
q =>
q.Kiosk.KioskId == kiosk.KioskId &&
(!q.RedesignedAt.HasValue||q.RedesignedAt.Value<= DateTime.Now))
.OrderByDescending(q => q.RedesignedAt)
.Take(1).Select(q => q.Type.DefinitionId).Contains(id)
);
这是问题。每个信息亭都有一个历史名称集合,在应用程序的某些部分我们希望根据其最新状态(通过检查其类型或活动或其他一些数据)做一些事情,所以这部分查询将重复:
db.KioskDesignations.Where(q =>
q.Kiosk.KioskId == kiosk.KioskId &&
(!q.RedesignedAt.HasValue || q.RedesignedAt.Value <= DateTime.Now))
.OrderByDescending(q => q.RedesignedAt).Take(1)
到目前为止,我已经尝试将此部分编写为函数,Func和Expression,并且它们都没有工作。请您告诉我如何重构此查询以便我可以重用重复部分? 非常感谢。
答案 0 :(得分:1)
你可以链接Wheres例如:
private void Something()
{
var query = GetStandardWhere(db.Kiosks);
query = query.Where( //some new criteria);
return query
.OrderByDescending(q => q.RedesignedAt)
.Take(1).Select(q => q.Type.DefinitionId).Contains(id)
);
}
private IQueryable<KioskDesignation> GetStandardWhere(IQueryable<KioskDesignation> query)
{
return
query.Where(
kiosk =>
db.KioskDesignations.Where(
q =>
q.Kiosk.KioskId == kiosk.KioskId &&
(!q.RedesignedAt.HasValue || q.RedesignedAt.Value <= DateTime.Now));
}
答案 1 :(得分:1)
我终于找到了解决办法:)
因为linq的where方法接受Func<T,bool>
,所以我编写了一个返回Func<T,bool>
的函数,并在我喜欢的地方调用它:
db.Kiosks
.Where(QueryCurrentKioskDesignation(db, d => d.Type.DefinitionId == id))
此函数获取一个Func作为谓词,根据其当前的Designation数据过滤我们的kiosk。 这是QueryCurrentKioskDesignation函数:
public static Func<Kiosk, bool> QueryCurrentKioskDesignation(DataContext db,
Func<KioskDesignation, bool> predicate)
{
return k => db.KioskDesignations.Where(q => q.Kiosk.KioskId == k.KioskId &&
(!q.RedesignedAt.HasValue ||
q.RedesignedAt.Value <= DateTime.Now))
.OrderByDescending(q => q.RedesignedAt)
.Take(1).Any(predicate);
}
<强>更新强>
我注意到只要我们使用IEnumerable<T>
,Linq方法就返回Func<>
(这意味着Linq立即调用函数并返回一个IEnumerable)但是最好使用表达式让Linq构建一个表达式树我们以后可以执行它。
为了实现这一点,我刚刚更改了QueryCurrentKioskDesignation签名以接受表达式并返回一个:
public static Expression<Func<Kiosk, bool>> QueryCurrentKioskDesignation(DataContext db,
Expression<Func<KioskDesignation, bool>> predicate)
现在我可以使用IQueryalbe并通过一个查询获取我想要的所有数据到数据库,并向您展示它的美妙之处在于我使用EFProf生成的查询
SELECT TOP (20) [Extent1].[KioskId] AS [KioskId],
[Extent1].[Code] AS [Code],
[Extent1].[Barcode] AS [Barcode],
[Extent1].[Notes] AS [Notes],
[Extent1].[CheckedAt] AS [CheckedAt],
[Extent1].[SearchKeywords] AS [SearchKeywords],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[CreatedBy] AS [CreatedBy],
[Extent1].[LastEditAt] AS [LastEditAt],
[Extent1].[LastEditBy] AS [LastEditBy],
[Extent1].[Guild_KioskGuildId] AS [Guild_KioskGuildId]
FROM [dbo].[Kiosks] AS [Extent1]
WHERE (EXISTS (SELECT 1 AS [C1]
FROM (SELECT TOP (1) [Project1].[Activity_DefinitionId] AS [Activity_DefinitionId]
FROM (SELECT [Extent2].[RedesignedAt] AS [RedesignedAt],
[Extent2].[Activity_DefinitionId] AS [Activity_DefinitionId]
FROM [dbo].[KioskDesignations] AS [Extent2]
WHERE ([Extent2].[Kiosk_KioskId] = [Extent1].[KioskId])
AND (([Extent2].[RedesignedAt] IS NULL)
OR ([Extent2].[RedesignedAt] <= (SysDateTime())))) AS [Project1]
ORDER BY [Project1].[RedesignedAt] DESC) AS [Limit1]
WHERE (CASE
WHEN (0 /* @p__linq__0 */ = 1) THEN
CASE
WHEN (14 = [Limit1].[Activity_DefinitionId]) THEN cast(1 as bit)
WHEN (14 <> [Limit1].[Activity_DefinitionId]) THEN cast(0 as bit)
END
WHEN (14 <> [Limit1].[Activity_DefinitionId]) THEN cast(1 as bit)
WHEN (14 = [Limit1].[Activity_DefinitionId]) THEN cast(0 as bit)
END) = 1))
AND (EXISTS (SELECT 1 AS [C1]
FROM (SELECT TOP (1) [Project3].[Type_DefinitionId] AS [Type_DefinitionId]
FROM (SELECT [Extent3].[RedesignedAt] AS [RedesignedAt],
[Extent3].[Type_DefinitionId] AS [Type_DefinitionId]
FROM [dbo].[KioskDesignations] AS [Extent3]
WHERE ([Extent3].[Kiosk_KioskId] = [Extent1].[KioskId])
AND (([Extent3].[RedesignedAt] IS NULL)
OR ([Extent3].[RedesignedAt] <= (SysDateTime())))) AS [Project3]
ORDER BY [Project3].[RedesignedAt] DESC) AS [Limit2]
WHERE [Limit2].[Type_DefinitionId] = 4 /* @p__linq__1 */))
这就是我爱Linq的原因:)。