[C#] Datumsspanne überprüfen

Fluffy_Unicorn

Met-Brauer
Registriert
8 Aug. 2013
Beiträge
605
Ort
47.07°N / 7.85°O
Morgäääähhhhhnnnn liebe ngb-Gemeinde

Ich habe ein kleines Problem, oder vielleicht auch nur eine Denkblockade. In der Schulle müssen wir zur Zeit ein C#-Projekt mit EntityFramework und WPF umsetzen. Nun hänge ich bei einer bestimmten Stelle.

Im Projekt geht es um eine Objektvermietung. Wenn ich ein Objekt vermiete, muss ich natürlich überprüfen, ob die gewünschten Daten noch frei sind.

Beispiel:
Objekt ist vermietet vom 18.12.2013 - 21.12.2013
Gewünschte Mietspanne vom Benutzer: 22.12.2013 - 28.12.2013

Dies sollte natürlich keinen Fehler verursachen (21.12.2013 - 28.12.2013 sollte aber ein Fehler geben).

Mein Ansatz:

Wenn
gewünschtes Startdatum grösser als Ende der Vermietung
Oder
gewünschtes Enddatum kleiner als Anfang der Vermietung
= Erfolg

Dies klappt aber noch nicht ganz.
Mein Code (datePickerTo & DatePickerFrom sind dabei die Benutzereingaben):

[src=csharp]
IQueryable<vermietung> vermietungQuery = from vermietung
in vermietungContext.vermietung
where (vermietung.Startdatum > datePickerTo.SelectedDate
|| vermietung.Enddatum < datePickerFrom.SelectedDate)
&& vermietung.Objekt_id.Equals(object_id)
select vermietung;
[/src]

Wenn dann kein Datensatz gefunden wurde, kann die Vermietung vorgenommen werden.

Ich weiss nicht was falsch ist, wahrscheinlich stehe ich nur auf dem Schlauch irgendwie. Vielleicht ist auch mein gesamter Ansatz falsch.

Schonmal danke für eure Hilfe.
Gruss
 
Wenn
gewünschtes Startdatum grösser als Ende der Vermietung
Oder
gewünschtes Enddatum kleiner als Anfang der Vermietung
= Erfolg

Eigentlich hast du die Fälle:

-) Wenn keine bisherige Buchung erfolgt ist (leeres Result)
ODER
-) Wenn das Start Datum Größer als das vorherige End-Datum UND das End-Datum größer als das neue Start-Datum ist

==> Gültige Reservierung

Bei gewünschten Enddatum < Anfang der Vermietung würdest du zurück in die Zeit gehen und es wäre somit kein gültiges Datum.
 
  • Thread Starter Thread Starter
  • #3
Danke schonmal für die Antwort :)

Bei gewünschten Enddatum < Anfang der Vermietung würdest du zurück in die Zeit gehen und es wäre somit kein gültiges Datum.

Nein, denn eine Reservation kann auch im voraus getätigt werden. Wenn ich heute für Januar reserviere, muss ich trotzdem im Dezember noch reservieren können.
 
Ich sehe... eigentlich brauchst du ja 2 Datensätze. Folgendes Beispiel:

1.12 - 8.12
15.12 - 24.12
7.1. - 14.1

Das Datum welches du einspielen willst ist jetzt der 9.12 bis 14.12. Du überprüfst den ersten Datensatz, das neue Startdatum ist größer als das Enddatum, das passt soweit. Dann nimmst du dir den nächsten Datensatz her und überprüfst, ob das End-Datum kleiner als das Startdatum ist. Ist es kleiner hast du Erfolg, ist es größer oder gleich kannst du nicht reservieren. Sprich 9.12 - 14.12 würde funktionieren aber 9.12 bis 15.12 kannst du knicken.
 
  • Thread Starter Thread Starter
  • #5
Was meinst du mit 2 Datensätze?
Mit meiner SQL-Abfrage will ich ja diese Datensätze auslesen, die eine Kollision verursachen. Wenn es dann keine Kollision findet kann das Objekt vermietet werden.

9.12 bis 15.12 soll auch nicht gehen, da es ja ab dem 15.12 vermietet ist.

Bin wahrscheinlich grad etwas schwer von Begriff, entschuldigung dafür ;).
 
Ah, ich habe den Sinn deiner Abfrage falsch verstanden. Ich bin davon ausgegangen das du dir einfach 2 nahe gelegene Termine raussuchen willst und die dann manuell überprüfst und nicht über das Statement selbst abfragen möchtest. Ich muss das dann kurz durchdenken wie das am Besten funktioniert...

Boah das ist eine gewaltige Kopfnuss. Das Problem ist nämlich die Oder-Abfrage: Suchst du nur nach der Start-Zeit würdest du die Datensätze,die deine Bedingung (Startzeit > Endzeit) erfüllen, bekommen. Sprich im nachfolgenden Fall:

1.12 - 8.12
15.12 - 24.12
7.1. - 14.1

start > ende -> 1.12 - 8.12 würdest du als Datensatz bekommen


Da du jedoch eine Oder-Abfrage in deiner Abfrage drinnen hast kriegst du zusätzlich auch die Datensätze zurück wo das Ende < Starttermin ist - sprich bei 3 Einträgen kriegst du alle 3 wieder zurück, 1 von dem Start und 2 vom Ende.

Du brauchst also 2 Selects, einmal das du die Datensätze bekommst wo das Start-Datum größer als das End-Datum ist und dann eine wo das End-Datum kleiner als das Start-Datum ist. Sprich das wäre dann in Select 1 1.12 - 8.12 und in Select 2 15.12 - 24.12 sowie 7.1 bis 14.1. Jetzt müsstest du eigentlich von Statement 1 den letztmöglichen Eintrag nehmen (kann ja Zeiten davor auch existieren) und von Statement 2 den ersten Eintrag (ist der nächste Termin). Diese beiden müsstest du dann mit deinem neuen Datum vergleichen damit du siehst ob es da zu einem Problem wg. Terminüberschneidung kommt.

Meiner Meinung nach solltest du aber diese Überprüfung dann in deinem Code machen, sprich einfach die notwendigen Daten aus der DB ziehen und dann erst mit dem Datum abgleichen. Ist einfach "schöner" als da dir aus 2 Selects ein Ergebnis via Subselects zusammenzustoppeln und das dann zu verwursteln.
 
Zuletzt bearbeitet:
Eigentlich trivial...

Es sind 3 Fälle möglich:
- Ein Startdatum liegt innerhalb des Zeitraums
- Ein Enddatum liegt innerhalb des Zeitraums
- Für einen einzelnen Eintrag liegt sowohl das Startdatum vor, als auch das Enddatum nach dem gewünschten Zeitraum

In allen 3 Fällen liegt eine Kollision vor, es gilt also:
[src=postgresql](reservierungen.startdatum BETWEEN date1 AND date2) OR (reservierungen.enddatum BETWEEN date1 AND date2) OR (reservierungen.startdatum <= date1 AND reservierungen.enddatum >= date2)[/src]
 
Mein Ansatz:
Wenn
gewünschtes Startdatum grösser als Ende der Vermietung [2]
Oder
gewünschtes Enddatum kleiner als Anfang der Vermietung [1]
= Erfolg
Grundsätzlich korrekt. Wenn du das jedoch so in LINQ-Notation überträgst
vermietung.Startdatum > datePickerTo.SelectedDate || vermietung.Enddatum < datePickerFrom.SelectedDate
selektierst du damit genau die Datensätze, welche unproblematisch sind. In deinem Beispiel würde die Abfrage bei einem Datenbestand von
1.12 - 8.12
15.12 - 24.12
7.1 - 14.1
und der Eingabe `9.12 - 15.12` die Resultate `1.12 - 8.12` (aufgrund von Bedingung 2) und `7.1 - 14.1` (aufgrund von Bedingung 1) liefern. Für `9.12 - 14.12` wäre das Ergebnis die komplette Liste, d.h. alle Einträge sind unproblematisch und die Buchung somit möglich.

Du möchtest aber wohl eher diejenigen Vermietungen selektieren, mit der Eingabe kollidieren. Dazu musst du die Bedingung negieren:
(vermietung.Startdatum <= datePickerTo.SelectedDate) && (vermietung.Enddatum >= datePickerFrom.SelectedDate)

Nachtrag:
Es sind 3 Fälle möglich:
- Ein Startdatum liegt innerhalb des Zeitraums
- Ein Enddatum liegt innerhalb des Zeitraums
- Für einen einzelnen Eintrag liegt sowohl das Startdatum vor, als auch das Enddatum nach dem gewünschten Zeitraum
Stimmt, allerdings müsste Fluffy_Unicorns Ansatz ebenfalls funktionieren, da in jedem dieser Fälle auch mindestens eine seine Bedingungen verletzt würde. Seine Bedingung [2] ist äquivalent zur Aussage `Der gewünschte Zeitraum A ist vollständig nach einem bestimmten Vermietungszeitraum B`, Bedingung [1] zur Aussage `Der gewünschte Zeitraum A ist komplett vor einem bestimmten Vermietungszeitraum B`. Wenn eine der beide Bedingungen erfüllt ist, sind A und B kollisionsfrei/disjunkt.
 
Zuletzt bearbeitet:
  • Thread Starter Thread Starter
  • #9
Sehr gut, werde die Lösungsansätze bei Gelegenheit mal testen.

An das Between habe ich gar nicht gedacht, geht sicher auch einfacher damit.

Wieso hast du ein AND zwischen den zwei Bedingungen? Müsste das nicht ein OR sein?
 
Kugelfisch, wie intelligent ist LINQ? Weil das mit dem && habe ich auch überlegt, aber es sind ja eigentlich 2 Datensätze davon betroffen? Oder übersehe ich da das große Puzzlestück was mir gerade abgeht?
 
Wieso hast du ein AND zwischen den zwei Bedingungen? Müsste das nicht ein OR sein?
Nein, das ist eine Folge der Regeln von De Morgan, vgl. - es gilt
NOT (A OR B) = (NOT A) AND (NOT B)

Kugelfisch, wie intelligent ist LINQ? Weil das mit dem && habe ich auch überlegt, aber es sind ja eigentlich 2 Datensätze davon betroffen?
Weshalb sollten zwei Datensätze betroffen sein? Die Bedingung muss sich ja gegen jeden einzelnen Datensatz (Bestehend zumindest aus aus Startdatum, Enddatum und Objekt-ID) unabhängig prüfen lassen, denn schliesslich ist die Frage, ob sich zwei Zeiträume überschneiden, unabhängig von beliebigen weiteren Zeiträumen. Die AND-verknüpften WHERE-Bedingungen müssen alle erfüllt sein, damit sich ein Treffer ergibt.
 
*Bonk* Alles klar, ja, da hast du recht, ich hab mich zu sehr auf das "Zwischen zwei Daten" versteift.
 
  • Thread Starter Thread Starter
  • #14
So, habs getestet, und funktioniert einwandfrei.

Kugelfisch, du bist genial, danke vielmal ;).

Danke auch an alle anderen für die Hilfe.
 
Zurück
Oben