Linq使用dateFrom和dateTo连接两个实体

huangapple go评论63阅读模式
英文:

Linq join 2 entities by dateFrom and dateTo

问题

我有以下实体:

flights: [
  {
    ...
    "flightId": 1,
    "dateFrom": "2023-03-01",
    "dateTo": "2023-03-01",
    ...
  },
  {
    ...
    "flightId": 2,
    "dateFrom": "2023-03-03",
    "dateTo": "2023-03-03",
    ...
  }
]

hotels: [
  {
    ...
    "bookId": 1,
    "dateFrom": "2023-03-01",
    "dateTo": "2023-03-03",
    ...
  }
]

我的目标是得到类似以下的结果:

[
 {
   date : "2023-03-01",
   flights: [
       {
          "flightId": 1
       }
   ], 
   hotels: [
       {
          "bookId": 1,
       }
   ]
 },
 {
   date : "2023-03-02",
   flights: [], 
   hotels: [
       {
          "bookId": 1,
       }
   ]
 },
 {
   date : "2023-03-03",
   flights: [
       {
          "flightId": 2
       }
   ], 
   hotels: [
       {
          "bookId": 1,
       }
   ]
 }
]

请问我如何在 C# 中使用 LINQ 或其他方法将它们联接/分组,包括使用 dateFrom 和 dateTo,同时也包括那些日期不相等且介于其中的情况?

这样将显示每个日期上的航班/酒店信息。

我对 C#/.NET 相当新,请帮忙,谢谢。

英文:

Lets say I have these entities :

flights: [
  {
    ...
    "flightId": 1,
    "dateFrom": "2023-03-01",
    "dateTo": "2023-03-01",
    ...
  },
  {
    ...
    "flightId": 2,
    "dateFrom": "2023-03-03",
    "dateTo": "2023-03-03",
    ...
  }
]

hotels: [
  {
    ...
    "bookId": 1,
    "dateFrom": "2023-03-01",
    "dateTo": "2023-03-03",
    ...
  }
]

And my goal is to have something like :

[
 {
   date : "2023-03-01",
   flights: [
       {
          "flightId": 1
       }
   ], 
   hotels: [
       {
          "bookId": 1,
       }
   ]
 },
 {
   date : "2023-03-02",
   flights: [], 
   hotels: [
       {
          "bookId": 1,
       }
   ]
 },
 {
   date : "2023-03-03",
   flights: [
       {
          "flightId": 2
       }
   ], 
   hotels: [
       {
          "bookId": 1,
       }
   ]
 }
]

May I know how I can join / group those 2 using LINQ or any method in C#, using both dateFrom & dateTo, including those that dates aren't equal and in between as well ?

So it will show every date with either flights / hotels on it.

I'm fairly new to c# / .net so any help is appreciated. Thank you.

Edit : Here's my table

------User------
| Id | Name    
----------------
| 1  | John Doe
----------------

Flight---------------------------------
| Id | DateFrom   | DateTo     | UserId
---------------------------------------
| 1  | 2023-03-01 | 2023-03-01 | 1
---------------------------------------
| 2  | 2023-03-03 | 2023-03-03 | 1


Hotels---------------------------------
| Id | DateFrom   | DateTo     | UserId
---------------------------------------
| 1  | 2023-03-01 | 2023-03-03 | 1

答案1

得分: 1

这是使用MoreLINQFullJoin()扩展的解决方案:

var flights = new[] {
    new Flight(1, From: DateTime.Parse("2023-01-12"), To: DateTime.Parse("2023-01-15")),
    new Flight(2, From: DateTime.Parse("2023-01-14"), To: DateTime.Parse("2023-01-17"))
};
var hotels = new[] {
    new Hotel(3, From: DateTime.Parse("2023-01-10"), To: DateTime.Parse("2023-01-13")),
    new Hotel(4, From: DateTime.Parse("2023-01-11"), To: DateTime.Parse("2023-01-14"))
};

var flightsByDay = flights
    .SelectMany(f => Days(f.From, f.To), (flight, day) => (flight, day))
    .GroupBy(f => f.day, f => f.flight);

var hotelsByDay = hotels
    .SelectMany(h => Days(h.From, h.To), (hotel, day) => (hotel, day))
    .GroupBy(h => h.day, h => h.hotel);
    
var result = flightsByDay
    .FullJoin(
        hotelsByDay,
        f => f.Key,
        h => h.Key,
        fs => (day: fs.Key, flights: fs.ToArray(), hotels: Array.Empty<Hotel>()),
        hs => (day: hs.Key, flights: Array.Empty<Flight>(), hotels: hs.ToArray()),
        (fs, hs) => (day: fs.Key, flights: fs.ToArray(), hotels: hs.ToArray()))
    .OrderBy(x => x.day);

static IEnumerable<DateTime> Days(DateTime from, DateTime to) => Enumerable
    .Range(0, 1 + to.Subtract(from).Days)
    .Select(offset => from.AddDays(offset));

public record Flight(int Id, DateTime From, DateTime To);
public record Hotel(int Id, DateTime From, DateTime To);

如果你在LINQPad中运行result.Dump(),你会看到以下结果:

Linq使用dateFrom和dateTo连接两个实体

英文:

Here's a solution using MoreLINQ's FullJoin() extension:

var flights = new[] {
    new Flight(1, From: DateTime.Parse(&quot;2023-01-12&quot;), To: DateTime.Parse(&quot;2023-01-15&quot;)),
    new Flight(2, From: DateTime.Parse(&quot;2023-01-14&quot;), To: DateTime.Parse(&quot;2023-01-17&quot;))
};
var hotels = new[] {
    new Hotel(3, From: DateTime.Parse(&quot;2023-01-10&quot;), To: DateTime.Parse(&quot;2023-01-13&quot;)),
    new Hotel(4, From: DateTime.Parse(&quot;2023-01-11&quot;), To: DateTime.Parse(&quot;2023-01-14&quot;))
};

var flightsByDay = flights
    .SelectMany(f =&gt; Days(f.From, f.To), (flight, day) =&gt; (flight, day))
    .GroupBy(f =&gt; f.day, f =&gt; f.flight);

var hotelsByDay = hotels
    .SelectMany(h =&gt; Days(h.From, h.To), (hotel, day) =&gt; (hotel, day))
    .GroupBy(h =&gt; h.day, h =&gt; h.hotel);
    
var result = flightsByDay
    .FullJoin(
        hotelsByDay,
        f =&gt; f.Key,
        h =&gt; h.Key,
        fs =&gt; (day: fs.Key, flights: fs.ToArray(), hotels: Array.Empty&lt;Hotel&gt;()),
        hs =&gt; (day: hs.Key, flights: Array.Empty&lt;Flight&gt;(), hotels: hs.ToArray()),
        (fs, hs) =&gt; (day: fs.Key, flights: fs.ToArray(), hotels: hs.ToArray()))
    .OrderBy(x =&gt; x.day);

static IEnumerable&lt;DateTime&gt; Days(DateTime from, DateTime to) =&gt; Enumerable
    .Range(0, 1 + to.Subtract(from).Days)
    .Select(offset =&gt; from.AddDays(offset));

public record Flight(int Id, DateTime From, DateTime To);
public record Hotel(int Id, DateTime From, DateTime To);

If you got LINQPad this is what you'll see for result.Dump():

Linq使用dateFrom和dateTo连接两个实体

huangapple
  • 本文由 发表于 2023年3月1日 16:03:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定