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

如何用LINQ跨表统计指定时段特定车辆的使用数量

问题描述

需要从两张表中统计指定时段内特定车辆的使用数量:

  • PostThr表存储服务时段信息
  • PostFiv表在FivCode为"V"时记录车辆类型信息
  • 两表通过ThrZero/FivZero字段关联
  • 查询条件:指定日期、开始时间、结束时间及车辆类型

已编写的PostThr筛选LINQ查询:

DateTime givenDate = DateTime.Parse("11/15/22");
TimeSpan givenTime = TimeSpan.Parse("9:00");
TimeSpan givenEndT = TimeSpan.Parse("13:00");
string vehicleType = "VAN";

var qry = from x in _context.PostThrs
          where
            x.ThrDate == givenDate &&
            x.ThrText == "SERVICE-" &&
            ((
            x.ThrTime < givenTime &&
            x.ThrEndT > givenTime
            ) || (
            x.ThrTime < givenEndT &&
            x.ThrEndT > givenEndT
            ))
            
            select x
            ;

尝试关联PostFiv的写法返回结果为0(实际应为2,11/14/22 9:00-18:00时段有2台VAN符合条件):

DateTime givenDate = DateTime.Parse("11/14/22");
TimeSpan givenTime = TimeSpan.Parse("9:00");
TimeSpan givenEndT = TimeSpan.Parse("18:00");

var qry = from x in _context.PostThrs
          where
            x.ThrDate == givenDate &&
            x.ThrText == "SERVICE-" &&
            ((
            x.ThrTime < givenTime &&
            x.ThrEndT > givenTime
            ) || (
            x.ThrTime < givenEndT &&
            x.ThrEndT > givenEndT
            )) select new { zero = x.ThrZero };

var ans = from y in qry join ex in _context.PostFivs on y.zero equals ex.FivZero select ex;

var oth = (from z in ans where z.FivCode == "V" && z.FivText == "VAN-" select z).Count();

var xyz = oth;

两张表的模型类定义(无导航属性):

PostThr模型

public class PostThr
{
    [Key]
    public int ThrId { get; set; }

    [ForeignKey("PostZero")]
    [Display(Name = "0/")]
    public string ThrZero { get; set; }

    [Display(Name = "Date*")]
    [DataType(DataType.Date)]
    public DateTime ThrDate { get; set; }

    [Display(Name = "Time")]
    public TimeSpan ThrTime { get; set; }

    [Display(Name = "End Time")]
    public TimeSpan ThrEndT { get; set; }

    [Required]
    [RegularExpression(@"[a-zA-Z0-9\"'\s-|\.\=\+\*\\/\\]*$")]
    [Display(Name = "Text")]
    [StringLength(160, MinimumLength = 2)]
    public string ThrText { get; set; }

    public string ThrTrackUser { get; set; }

    public string ThrTrackTime { get; set; }
}

PostFiv模型

public class PostFiv
{
    [Key]
    public int FivId { get; set; }

    [ForeignKey("PostZero")]
    [Display(Name = "0/")]
    public string FivZero { get; set; }

    [Required]
    [Display(Name = "Priority Number")]
    [StringLength(1, MinimumLength = 1)]
    public string FivPrio { get; set; }

    [Required]
    [Display(Name = "Code Letter")]
    [StringLength(1, MinimumLength = 1)]
    public string FivCode { get; set; }

    [Required]
    [RegularExpression(@"[a-zA-Z0-9\"'\s-|\.\=\+\*\\/\\/¥():]*$")]
    [Display(Name = "Remark Text")]
    [StringLength(2000, MinimumLength = 1)]
    public string FivText { get; set; }

    public string FivTrackUser { get; set; }

    public string FivTrackTime { get; set; }
}

需要正确的LINQ写法以得到准确的统计结果。


问题分析与解决方案

问题点

  1. 时段判断逻辑不全:原查询仅覆盖了目标时段与服务时段的部分重叠场景,漏掉了服务时段完全包含目标时段的情况,导致符合条件的记录被遗漏。
  2. 分步查询冗余:分步拉取数据再关联,不仅增加数据传输量,也容易出现逻辑疏漏。
  3. 字符串匹配需验证:需确保ThrText和FivText的匹配值与数据库实际存储内容一致。

正确LINQ写法

写法1:查询语法(可读性强)

DateTime givenDate = DateTime.Parse("11/14/22");
TimeSpan givenStartTime = TimeSpan.Parse("9:00");
TimeSpan givenEndTime = TimeSpan.Parse("18:00");
string targetVehicleType = "VAN";

var count = (from thr in _context.PostThrs
             join fiv in _context.PostFivs on thr.ThrZero equals fiv.FivZero
             where
                 thr.ThrDate == givenDate &&
                 thr.ThrText == "SERVICE-" &&
                 // 覆盖所有时段重叠场景
                 (
                     // 服务时段开始在目标时段内
                     (thr.ThrTime >= givenStartTime && thr.ThrTime <= givenEndTime) ||
                     // 服务时段结束在目标时段内
                     (thr.ThrEndT >= givenStartTime && thr.ThrEndT <= givenEndTime) ||
                     // 服务时段完全包含目标时段
                     (thr.ThrTime <= givenStartTime && thr.ThrEndT >= givenEndTime)
                 ) &&
                 fiv.FivCode == "V" &&
                 fiv.FivText.StartsWith("VAN-") // 根据实际数据调整,也可直接用等于
             select thr.ThrZero) // 按ThrZero去重,避免同一车辆重复计数
             .Distinct()
             .Count();

写法2:方法语法(简洁紧凑)

DateTime givenDate = DateTime.Parse("11/14/22");
TimeSpan givenStartTime = TimeSpan.Parse("9:00");
TimeSpan givenEndTime = TimeSpan.Parse("18:00");
string targetVehicleType = "VAN";

var count = _context.PostThrs
    .Join(_context.PostFivs,
          thr => thr.ThrZero,
          fiv => fiv.FivZero,
          (thr, fiv) => new { thr, fiv })
    .Where(x =>
        x.thr.ThrDate == givenDate &&
        x.thr.ThrText == "SERVICE-" &&
        // 完整时段重叠判断
        (x.thr.ThrTime >= givenStartTime && x.thr.ThrTime <= givenEndTime) ||
        (x.thr.ThrEndT >= givenStartTime && x.thr.ThrEndT <= givenEndTime) ||
        (x.thr.ThrTime <= givenStartTime && x.thr.ThrEndT >= givenEndTime) &&
        x.fiv.FivCode == "V" &&
        x.fiv.FivText.StartsWith("VAN-"))
    .Select(x => x.thr.ThrZero)
    .Distinct()
    .Count();

关键说明

  • 时段重叠判断:覆盖了所有可能的服务时段与目标时段的交集场景,确保无遗漏。
  • 去重处理:通过Distinct()基于ThrZero去重,避免同一车辆的多条关联记录被重复统计。
  • 字符串匹配:如果数据库中FivText存储的是纯"VAN"而非"VAN-",直接改为x.fiv.FivText == targetVehicleType即可,需与实际数据一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:50:37