1

我一直在尝试重构此查询一段时间,但没有任何运气:

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 和一个表达式,但它们都不起作用。请告诉我应该如何重构这个查询,以便我可以重用重复的部分?非常感谢。

4

2 回答 2

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));
    }
于 2013-06-05T17:56:13.080 回答
1

我终于找到了一个解决方案:) 因为 linq 的 Where 方法接受Func<T,bool>了,所以我编写了一个返回 a 的函数,Func<T,bool>并在我的 Where 中调用它,如下所示:

db.Kiosks
    .Where(QueryCurrentKioskDesignation(db, d => d.Type.DefinitionId == id))

此函数获取一个 Func 作为谓词,以根据其当前的指定数据过滤我们的信息亭。这是 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);
        }

更新: 我注意到 Linq 方法IEnumerable<T>在我们使用时返回一个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 的原因 :)

于 2013-06-05T21:10:18.903 回答