我建议离开自己加入你的桌子,以便在第二天获得关闭时间。我假设每一行都有零个或一个子行。我不使用表,而是使用数组,但查询应该是一样的。我在 LINQPad 中编写代码。
void Main()
{
var Timings = new []
{
new Timing(22, 0, new DateTime(2021, 9, 12, 9, 45, 0), new DateTime(2021, 9, 12, 11, 15, 0), null),
new Timing(23, 0, new DateTime(2021, 9, 12, 13, 0, 0), new DateTime(2021, 9, 12, 15, 0, 0), null),
new Timing(24, 1, new DateTime(2021, 9, 13, 9, 0, 0), new DateTime(2021, 9, 13, 23, 59, 59), null),
new Timing(31, 2, new DateTime(2021, 9, 14, 0, 0, 0), new DateTime(2021, 9, 14, 2, 0, 0), 24),
new Timing(25, 2, new DateTime(2021, 9, 14, 10, 0, 0), new DateTime(2021, 9, 14, 12, 0, 0), null),
new Timing(26, 2, new DateTime(2021, 9, 14, 15, 0, 0), new DateTime(2021, 9, 14, 17, 0, 0), null),
new Timing(28, 4, new DateTime(2021, 9, 16, 9, 45, 0), new DateTime(2021, 9, 16, 23, 15, 0), null),
new Timing(29, 5, new DateTime(2021, 9, 17, 9, 45, 0), new DateTime(2021, 9, 17, 23, 15, 0), null),
new Timing(30, 6, new DateTime(2021, 9, 18, 9, 45, 0), new DateTime(2021, 9, 18, 23, 15, 0), null),
};
var timingGroupedWithChildren = (
from t1 in Timings.Where(x => x.ParentId == null) // parent rows only
join t2 in Timings.Where(x => x.ParentId != null) // childr rows only
on t1.Id equals t2.ParentId // left join parent's Id with child's ParentId
into nextDay
select new {t1, nextDay})
.Dump() //unremark this line to get show the result in LINQPad
;
}
class Timing
{
public int Id {get; set;}
public int DayOfWeek {get; set;}
public DateTime OpenTime {get; set;}
public DateTime CloseTime {get; set;}
public int? ParentId {get; set;}
public Timing(int id, int dow, DateTime openTime, DateTime closeTime, int? parentId)
{
this.Id = id;
this.DayOfWeek = dow;
this.OpenTime = openTime;
this.CloseTime = closeTime;
this.ParentId = parentId;
}
}
timingGroupedWithChildren 如下所示:
请注意,只有 id = 24 有 nextDay,其他行没有 nextDay。有 8 个项目(显示在左上角),但仅详细显示了 Id 23 和 24(其他行折叠以节省空间,因为我的屏幕不够大)。
现在很容易得到第二天的关门时间。第一种方法是这样的。
void Main()
{
var Timings = new []
{
new Timing(22, 0, new DateTime(2021, 9, 12, 9, 45, 0), new DateTime(2021, 9, 12, 11, 15, 0), null),
new Timing(23, 0, new DateTime(2021, 9, 12, 13, 0, 0), new DateTime(2021, 9, 12, 15, 0, 0), null),
new Timing(24, 1, new DateTime(2021, 9, 13, 9, 0, 0), new DateTime(2021, 9, 13, 23, 59, 59), null),
new Timing(31, 2, new DateTime(2021, 9, 14, 0, 0, 0), new DateTime(2021, 9, 14, 2, 0, 0), 24),
new Timing(25, 2, new DateTime(2021, 9, 14, 10, 0, 0), new DateTime(2021, 9, 14, 12, 0, 0), null),
new Timing(26, 2, new DateTime(2021, 9, 14, 15, 0, 0), new DateTime(2021, 9, 14, 17, 0, 0), null),
new Timing(28, 4, new DateTime(2021, 9, 16, 9, 45, 0), new DateTime(2021, 9, 16, 23, 15, 0), null),
new Timing(29, 5, new DateTime(2021, 9, 17, 9, 45, 0), new DateTime(2021, 9, 17, 23, 15, 0), null),
new Timing(30, 6, new DateTime(2021, 9, 18, 9, 45, 0), new DateTime(2021, 9, 18, 23, 15, 0), null),
};
var timingGroupedWithChildren = (
from t1 in Timings.Where(x => x.ParentId == null) // parent rows only
join t2 in Timings.Where(x => x.ParentId != null) // childr rows only
on t1.Id equals t2.ParentId // left join parent's Id with child's ParentId
into nextDay
select new {
t1.Id,
t1.DayOfWeek,
t1.OpenTime,
// if current row's next day is null, then use current row's CloseTime
// otherwise use next day's CloseTime
CloseTime = nextDay.Where(x => x.ParentId == t1.Id).Count() == 0 ? t1.CloseTime : nextDay.Where(x => x.ParentId == t1.Id).Single().CloseTime
})
//.Dump() //unremark this line to get show the result in LINQPad
;
var myShift = timingGroupedWithChildren.Where(x => x.Id == 24).Single();
var myWorkingHours = (myShift.CloseTime - myShift.OpenTime).TotalHours;
Console.WriteLine($"Working hours = {myWorkingHours}");
}
class Timing
{
public int Id {get; set;}
public int DayOfWeek {get; set;}
public DateTime OpenTime {get; set;}
public DateTime CloseTime {get; set;}
public int? ParentId {get; set;}
public Timing(int id, int dow, DateTime openTime, DateTime closeTime, int? parentId)
{
this.Id = id;
this.DayOfWeek = dow;
this.OpenTime = openTime;
this.CloseTime = closeTime;
this.ParentId = parentId;
}
}
您可以在下面的图片中看到,如果当前行有孩子,我会替换结束日。但我不使用实际数据库测试此查询(我使用的是数组),我不喜欢调用 nextDay.Where(x => ...).Count() 两次,因为 LINQ 中的某些方法,例如. Count(),迭代所有行。它是用 Where(x => ...) 过滤的,但除非我看到调用此查询时执行的实际 SQL 语句,否则我什么也说不出来。如果在 SQL Management Studio 中打开 SQL Profiler 或使用 LINQPad SQL 翻译,则可以看到实际语句。该按钮位于图片顶部(结果 lambda 符号 SQL IL 树)。
另一种方法是在从 SQL 获取数据后获取子行并执行 Count()。
void Main()
{
var Timings = new []
{
new Timing(22, 0, new DateTime(2021, 9, 12, 9, 45, 0), new DateTime(2021, 9, 12, 11, 15, 0), null),
new Timing(23, 0, new DateTime(2021, 9, 12, 13, 0, 0), new DateTime(2021, 9, 12, 15, 0, 0), null),
new Timing(24, 1, new DateTime(2021, 9, 13, 9, 0, 0), new DateTime(2021, 9, 13, 23, 59, 59), null),
new Timing(31, 2, new DateTime(2021, 9, 14, 0, 0, 0), new DateTime(2021, 9, 14, 2, 0, 0), 24),
new Timing(25, 2, new DateTime(2021, 9, 14, 10, 0, 0), new DateTime(2021, 9, 14, 12, 0, 0), null),
new Timing(26, 2, new DateTime(2021, 9, 14, 15, 0, 0), new DateTime(2021, 9, 14, 17, 0, 0), null),
new Timing(28, 4, new DateTime(2021, 9, 16, 9, 45, 0), new DateTime(2021, 9, 16, 23, 15, 0), null),
new Timing(29, 5, new DateTime(2021, 9, 17, 9, 45, 0), new DateTime(2021, 9, 17, 23, 15, 0), null),
new Timing(30, 6, new DateTime(2021, 9, 18, 9, 45, 0), new DateTime(2021, 9, 18, 23, 15, 0), null),
};
var timingGroupedWithChildren = (
from t1 in Timings.Where(x => x.ParentId == null) // parent rows only
join t2 in Timings.Where(x => x.ParentId != null) // childr rows only
on t1.Id equals t2.ParentId // left join parent's Id with child's ParentId
into nextDay
select new {
t1.Id,
t1.DayOfWeek,
t1.OpenTime,
t1.CloseTime,
NextDay = nextDay
})
//.Dump() //unremark this line to get show the result in LINQPad
;
var myShift = timingGroupedWithChildren.Where(x => x.Id == 24).Single();
var myWorkingHours = ((myShift.NextDay.Count() == 0 ? myShift.CloseTime : myShift.NextDay.Single().CloseTime) - myShift.OpenTime).TotalHours;
Console.WriteLine($"Working hours = {myWorkingHours}");
}
class Timing
{
public int Id {get; set;}
public int DayOfWeek {get; set;}
public DateTime OpenTime {get; set;}
public DateTime CloseTime {get; set;}
public int? ParentId {get; set;}
public Timing(int id, int dow, DateTime openTime, DateTime closeTime, int? parentId)
{
this.Id = id;
this.DayOfWeek = dow;
this.OpenTime = openTime;
this.CloseTime = closeTime;
this.ParentId = parentId;
}
}
您可以看到只有 Id = 24 的行具有 NextDay(如图片 #1)。