You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在EF查询中基于Hour筛选进一步返回营业的Place实体

问题:筛选当前处于营业时间内的Place实体

我知道我的问题表述有些模糊,因为暂时找不到更清晰的提问方式,但确定这并非难以解决的问题。

具体场景如下:
我需要在实体仓储的GetAllPlaces方法中返回List<Place>集合。

Place实体定义

public Guid PlaceId { get; set; }
public string Name { get; set; }
public Point Location { get; set; }
public bool IsOpen { get; set; }
public List<Event> Events { get; set; }
public List<Hour> Hours { get; set; }

Hour实体定义

public Guid HourId { get; set; }
public Guid DayOfTheWeekId { get; set; }
public DayOfTheWeek DayOfTheWeek { get; set; }
public DateTime OpenHour { get; set; }
public DateTime CloseHour { get; set; }
public Guid PlaceId { get; set; }
public Place Place { get; set; }

每个Place实体包含List<Hour>属性,我希望通过筛选该列表,不向调用方返回当前处于关闭状态的场所。目前已实现的逻辑是:仅包含该Place所在时区当天对应的Hour数据:

public async Task<IReadOnlyList<Place>>
            GetAllPlacesAsync(
            double lat,
            double lon,
            string userCity,
            double visibleRadius)
        {    
            var geometryFactory =
            NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
        var userLocation = geometryFactory
            .CreatePoint(new Coordinate(lon, lat));

            var places = await context.Places
                .AsNoTracking()

                .Include(s => s.Hours
                    // 此处筛选出前文所述的当天Hour数据
                    .Where(d => d.DayOfTheWeek.DayName
                        == TimeZoneInfo
                        .ConvertTime(DateTime.Now,
                            TimeZoneInfo
                            .FindSystemTimeZoneById(d.Place.Timezone.Name))
                            .DayOfWeek
                            .ToString()).FirstOrDefault())
                // 第二个.Where()会筛选Include的数据或places集合,但无法针对Hours进行过滤
                // 我希望实现的逻辑是:
                // 如果Place.Hour.Open <= 场所时区当前时间
                // && Place.Hour.Close >= 场所时区当前时间,则保留,否则排除

                .Where(
            x => x.Address.City == userCity
            && x.Location.IsWithinDistance(userLocation, visibleRadius))
                .Distinct()
                .ToListAsync();

            return places;
        }

请问如何进一步筛选,仅保留其当天所在时区营业时间内的Place实体?


编辑1

感谢@TN的解答,我编写了如下SQL存储过程:

CREATE PROCEDURE spUpdateIsOpenAndSelectForMap
@UserLat DOUBLE PRECISION,
@UserLon DOUBLE PRECISION,
@PlaceLat DOUBLE PRECISION,
@PlaceLon DOUBLE PRECISION,
@UserCity NVARCHAR(100),
@VisibleRadius DOUBLE PRECISION,
@PlaceToUserDistance DOUBLE PRECISION,
@UserLocation GEOGRAPHY,
@PlaceLocation GEOGRAPHY
AS
BEGIN

SET NOCOUNT ON;

DECLARE @SRID INT;
SET @SRID = 4326; -- 单位:米

-- 创建用户位置和场所位置的地理信息,以及两者间的距离
-- 后续返回距离小于可见半径的场所
SET @UserLocation = geography::Point(@UserLat, @UserLon, @SRID);
SET @PlaceLocation = geography::Point(@PlaceLat, @PlaceLon, @SRID);
SET @PlaceToUserDistance = @UserLocation.STDistance(@PlaceLocation)

-- 待办事项
-- 创建新表PlacePinOnMap

-- 更新IsOpen属性
UPDATE [P]
SET [IsOpen] = [OpenTimeCalc].[IsOpen]

-- 当用户执行该存储过程并更新IsOpen属性后,返回包含更新数据的结果集
-- 用于在代码中转换为DTO
OUTPUT [P].[PlaceId],
       [P].[Location],
       [P].[Latitude],
       [P].[Longitude],
       INSERTED.[IsOpen],
       [M].[Name],
       [E].[EC]

FROM [Places] [P]
JOIN [Timezones] [TZ] ON [TZ].[TimezoneId] = [P].[TimezoneId]
CROSS APPLY (
    -- 获取场所时区的本地日期时间
    SELECT
        GETUTCDATE() AT TIME ZONE 'UTC' AT TIME ZONE [TZ].[Name] AS [LocalDateTime]
) [LT]
CROSS APPLY (
    -- 获取场所时区的本地星期名称和本地时间
    SELECT
        DATENAME(WEEKDAY, [LT].[LocalDateTime]) AS [LocalWeekdayName],
        CAST([LT].[LocalDateTime] AS [TIME]) AS [LocalTime]
) [DT]
CROSS APPLY (
    -- 获取未来事件的数量
    SELECT
        COUNT(*)
        FROM [Events] [E]
        WHERE [E].[Date] >= [LT].[LocalDateTime]
) [EC]
JOIN [DaysOfTheWeek] [DOW] ON [DOW].[DayName] = [DT].[LocalWeekdayName]
JOIN [Moods] AS [M] ON [P].[MoodId] = [M].[MoodId]
-- 同时获取与场所关联的事件
JOIN [Events] AS [E] ON [P].[PlaceId] = [E].[PlaceId]
CROSS APPLY (
    -- 筛选出本地时间处于当日营业时间内的场所
    SELECT CASE WHEN EXISTS (
        SELECT *
        FROM [StoreHours] [SH]
        WHERE [SH].[PlaceId] = [P].[PlaceId]
        AND [SH].[DayOfTheWeekId] = [DOW].[DayOfTheWeekId]
        AND [SH].[OpenHour] <= [DT].[LocalTime]
        -- 特殊情况:24:00的关门时间存储为00:00,因为TIME类型不支持24:00
        AND ([SH].[CloseHour] > [DT].[LocalTime] OR [SH].[CloseHour] = '00:00')
    ) THEN 1 ELSE 0 END AS [IsOpen]
) [OpenTimeCalc]
WHERE ([P].[IsOpen] <> [OpenTimeCalc].[IsOpen])
AND ([P].[Address].[City] = @UserCity)
AND (@PlaceToUserDistance <= @VisibleRadius);

END

内容的提问来源于stack exchange,提问作者Jimmy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:35:30