Ich versuche, ein .NET TimeSpan
in SQL Server 2008 R2 zu speichern .
EF Code First scheint vorzuschlagen, dass es als Time(7)
in SQL gespeichert werden sollte .
In TimeSpan
.Net können jedoch längere Zeiträume als 24 Stunden verarbeitet werden.
Was ist der beste Weg, um .Net TimeSpan
in SQL Server zu speichern ?
.net
sql-server
timespan
GraemeMiller
quelle
quelle
Antworten:
Ich würde es in der Datenbank als
BIGINT
speichern und die Anzahl der Ticks speichern (z. B. TimeSpan.Ticks- Eigenschaft).Auf diese Weise könnte ich, wenn ich beim Abrufen ein TimeSpan-Objekt erhalten möchte, einfach TimeSpan.FromTicks (Wert) ausführen, was einfach wäre.
quelle
SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME)
. Das'1900-01-01'
Datum spielt natürlich keine Rolle, es ist nur die dritte Variable, die von derDATEADD(...)
Funktion benötigt wird . Denken Sie daran, dass ein Tick 100 Nanosekunden enthält. Wenn Sie jedoch verwendenDATEADD(NANOSECOND...
, tritt wahrscheinlich ein Überlauf auf, sodass Millisekunden verwendet werden. Denken Sie auch daran, dass Sie diese Tatsache mit C #TimeSpan.TicksPerMillisecond
(sollte 10000 sein) überprüfen sollten, um sicherzugehen.Danke für den Hinweis. Da es in SQL Server kein Äquivalent gibt. Ich habe einfach ein zweites Feld erstellt, das die Zeitspanne in Ticks konvertiert und in der Datenbank gespeichert hat. Ich habe dann das Speichern der TimeSpan verhindert
quelle
Wenn Sie nicht mehr als 24 Stunden speichern müssen , können Sie nur die Zeit speichern , da SQL Server 2008 und höher die Zuordnung ist
time (SQL Server) <-> TimeSpan(.NET)
Keine Konvertierungen erforderlich, wenn Sie nur 24 Stunden oder weniger speichern müssen.
Quelle: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
Aber , wenn Sie mehr als 24 Stunden speichern möchten, gehen Sie Notwendigkeit , sie in Zecken zu speichern, die Daten abrufen und dann in Timespan zu konvertieren. Beispielsweise
quelle
Time
Typ soll nicht eine Dauer darstellen, sondern den Zeitteil eines DateTime-Werts. Es ist eine schreckliche Wahl fürTimeSpan
.Es gibt kein direktes Äquivalent. Speichern Sie es einfach numerisch, z. B. Anzahl der Sekunden oder etwas, das Ihrer gewünschten Genauigkeit entspricht.
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich wollte sicherstellen, dass einige andere Optionen angegeben werden.
Da Sie eine Zeitspanne von nicht mehr als 24 Stunden in einem Zeit-SQL-Datentypfeld speichern können; ein paar andere Optionen könnten sein.
Verwenden Sie einen Varchar (xx), um den ToString des TimeSpan zu speichern. Dies hat den Vorteil, dass die Genauigkeit nicht in den Datentyp oder die Berechnung integriert werden muss (Sekunden gegenüber Millisekunden gegenüber Tagen gegenüber vierzehn Tagen). Sie müssen lediglich TimeSpan.Parse / TryParse verwenden. Das würde ich tun.
Verwenden Sie ein zweites Datum, Datum / Uhrzeit oder Datum / Uhrzeit-Versatz, in dem das Ergebnis des ersten Datums + der Zeitspanne gespeichert wird. Das Lesen aus der Datenbank ist eine Frage von TimeSpan x = SecondDate - FirstDate. Wenn Sie diese Option verwenden, werden Sie vor anderen Nicht-.NET-Datenzugriffsbibliotheken geschützt, die auf dieselben Daten zugreifen, TimeSpans jedoch nicht verstehen. falls Sie eine solche Umgebung haben.
quelle
Um mit der wahrscheinlich wahrscheinlichsten Quelle für die Generierung einer Zeitspanne übereinzustimmen (Berechnung der Differenz von zwei oder Datums- und Uhrzeitangaben), möchten Sie möglicherweise .NET
TimeSpan
als SQL Server-DateTime
Typ speichern .Dies liegt daran, dass in SQL Server die Differenz von 2
DateTime
(Cast
zuFloat
'und dannCast
zurück zu aDateTime
) einfachDateTime
relativ zum 1. Januar 1900 ist. Eine Differenz von +0,1 Sekunden wäre der 1. Januar 1900 00: 00: 00.100 und -0,1 Sekunden wäre der 31. Dezember 1899 23: 59: 59.900.Um ein .NET
TimeSpan
in einen SQL Server-DateTime
Typ zu konvertieren, konvertieren Sie es zunächst in einen .NET-DateTime
Typ, indem Sie es einemDateTime
vom 1. Januar 1900 hinzufügen. Wenn Sie es von SQL Server in .NET einlesen, müssen Sie dies zunächst tun Lesen Sie es in ein .NETDateTime
und subtrahieren Sie dann den 1. Januar 1900 davon, um es in ein .NET zu konvertierenTimeSpan
.In Anwendungsfällen, in denen die Zeitspannen von SQL Server
DateTime
und innerhalb von SQL Server (dh über T-SQL) generiert werden und SQL Server vor 2016 liegt, ist es je nach Reichweite und Genauigkeitsanforderungen möglicherweise nicht sinnvoll, sie zu speichern als Millisekunden (ganz zu schweigen davonTicks
), weil derInt
Typ, der vonDateDiff
(im Vergleich zuBigInt
SS 2016 +DateDiff_Big
) zurückgegeben wurde, nach ~ 24 Tagen im Wert von Millisekunden und ~ 67 Jahren überläuft. von Sekunden. Während diese Lösung Zeitspannen mit einer Genauigkeit von bis zu 0,1 Sekunden und von -147 bis +8.099 Jahren handhabt.WARNHINWEISE:
Dies würde nur funktionieren, wenn der Unterschied zum 1. Januar 1900 zu einem Wert im Bereich eines SQL Server-
DateTime
Typs führen würde (1. Januar 1753 bis 31. Dezember 9999, auch bekannt als -147 bis +8.099 Jahre). Wir müssen uns auf der .NET-TimeSpan
Seite nicht so viele Sorgen machen , da es ~ 29 k bis +29 k Jahre halten kann. Ich habe den SQL Server-DateTime2
Typ (dessen Bereich auf der negativen Seite viel größer ist als der von SQL ServerDateTime
) nicht erwähnt, weil: a) er nicht über einen einfachen in einen numerischen Bereich konvertiert werden kannCast
und b)DateTime
der Bereich ausreichen sollte für die überwiegende Mehrheit der Anwendungsfälle.SQL Server-
DateTime
Unterschiede, die mit der MethodeCast
- to -Float
- und - back berechnet wurden, scheinen nach 0,1 Sekunden nicht genau zu sein.quelle
Es gibt mehrere Möglichkeiten, eine Zeitspanne in der Datenbank darzustellen.
Zeit
Dieser Datentyp wird seit SQL Server 2008 unterstützt und ist die bevorzugte Methode zum Speichern von a
TimeSpan
. Es ist keine Zuordnung erforderlich. Es funktioniert auch gut mit SQL-Code.Wie in der ursprünglichen Frage angegeben, ist dieser Datentyp jedoch auf 24 Stunden begrenzt.
datetimeoffset
Der
datetimeoffset
Datentyp wird direkt zugeordnetSystem.DateTimeOffset
. Es wird verwendet, um den Versatz zwischen einemdatetime
/datetime2
zu UTC auszudrücken , aber Sie können ihn auch für verwendenTimeSpan
.Da der Datentyp jedoch eine sehr spezifische Semantik vorschlägt, sollten Sie auch andere Optionen in Betracht ziehen.
datetime / datetime2
Ein Ansatz könnte darin bestehen, die Typen
datetime
oder zudatetime2
verwenden. Dies ist am besten in Szenarien, in denen Sie die Werte in der Datenbank direkt verarbeiten müssen, d. H. für Ansichten, gespeicherte Prozeduren oder Berichte. Der Nachteil ist, dass Sie den WertDateTime(1900,01,01,00,00,00)
vom Datum abziehen müssen, um die Zeitspanne in Ihrer Geschäftslogik wiederherzustellen .Bigint
Ein anderer Ansatz könnte darin bestehen, die Zeitspanne in Ticks zu konvertieren und den
bigint
Datentyp zu verwenden. Dieser Ansatz hat jedoch den Nachteil, dass die Verwendung in SQL-Abfragen umständlich ist.Varchar (N)
Dies ist am besten für Fälle geeignet, in denen der Wert für den Menschen lesbar sein sollte. Sie können dieses Format auch in SQL-Abfragen verwenden, indem Sie die
CONVERT(datetime, ValidityPeriod)
Funktion verwenden. Abhängig von der erforderlichen Genauigkeit benötigen Sie zwischen 8 und 25 Zeichen.Bonus: Zeitraum und Dauer
Mithilfe einer Zeichenfolge können Sie auch NodaTime- Datentypen speichern , insbesondere
Duration
undPeriod
. Die erste ist im Grunde die gleiche wie eine Zeitspanne, während die spätere berücksichtigt, dass einige Tage und Monate länger oder kürzer sind als andere (dh der Januar hat 31 Tage und der Februar 28 oder 29; einige Tage sind wegen der Sommerzeit länger oder kürzer ). In solchen Fällen ist die Verwendung eines TimeSpan die falsche Wahl.Mit diesem Code können Sie Perioden konvertieren:
Und dann benutze es gerne
ich mag wirklich
NodaTime
es und es erspart mir oft knifflige Fehler und viele Kopfschmerzen. Der Nachteil hierbei ist, dass Sie es wirklich nicht in SQL-Abfragen verwenden können und Berechnungen im Arbeitsspeicher durchführen müssen.Benutzerdefinierter CLR-Typ
Sie haben auch die Möglichkeit, einen benutzerdefinierten Datentyp zu verwenden und eine benutzerdefinierte
TimeSpan
Klasse direkt zu unterstützen. Weitere Informationen finden Sie unter Benutzerdefinierte CLR-Typen .Der Nachteil hierbei ist, dass sich der Datentyp möglicherweise nicht gut mit SQL-Berichten verhält. Einige Versionen von SQL Server (Azure, Linux, Data Warehouse) werden ebenfalls nicht unterstützt.
Wertumwandlungen
Beginnend mit EntityFramework - Core 2.1, haben Sie die Möglichkeit , verwenden Wert Conversions .
Wenn Sie dies verwenden, kann EF jedoch nicht viele Abfragen in SQL konvertieren , was dazu führt, dass Abfragen im Arbeitsspeicher ausgeführt werden. möglicherweise viele, viele Daten in Ihre Anwendung übertragen.
Zumindest für den Moment ist es möglicherweise besser, es nicht zu verwenden und das Abfrageergebnis einfach mit Automapper abzubilden .
quelle
Normalerweise speichere ich einen TimeSpan als Bigint, der mit Ticks aus der TimeSpan.Ticks-Eigenschaft gefüllt ist, wie zuvor vorgeschlagen. Sie können einen TimeSpan auch als varchar (26) speichern, der mit der Ausgabe von TimeSpan.ToString () gefüllt ist. Die vier Skalarfunktionen (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks), die ich geschrieben habe, sind hilfreich für die Behandlung von TimeSpan auf der SQL-Seite und vermeiden die Hacks, die künstlich begrenzte Bereiche erzeugen würden. Wenn Sie das Intervall überhaupt in einem .NET TimeSpan speichern können, sollte es auch mit diesen Funktionen funktionieren. Darüber hinaus können Sie mit den Funktionen mit TimeSpans und 100-Nanosekunden-Ticks arbeiten, selbst wenn Sie Technologien verwenden, die .NET Framework nicht enthalten.
quelle