Usiłuję przechowywać .Net TimeSpan
w SQL Server 2008 R2.
Najpierw wydaje się, że kod EF sugeruje, że powinien być przechowywany jako Time(7)
SQL.
Jednak TimeSpan
w .Net może obsługiwać okresy dłuższe niż 24 godziny.
Jaki jest najlepszy sposób na przechowywanie .Net TimeSpan
w SQL Server?
.net
sql-server
timespan
GraemeMiller
źródło
źródło
Odpowiedzi:
Zapisałbym go w bazie danych jako
BIGINT
i zapisałbym liczbę znaczników (np. Właściwość TimeSpan.Ticks ).W ten sposób, gdybym chciał uzyskać obiekt TimeSpan podczas jego odzyskiwania, mógłbym po prostu zrobić TimeSpan.FromTicks (wartość), co byłoby łatwe.
źródło
SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME)
.'1900-01-01'
Data nie ma znaczenia, oczywiście, że to właśnie trzecia zmienna wymagane przezDATEADD(...)
funkcję. Pamiętaj, że w kleszczu znajduje się 100 nanosekund, ale jeśli go użyjeszDATEADD(NANOSECOND...
, prawdopodobnie wystąpi przepełnienie, dlatego używasz milisekund. Pamiętaj również, że powinieneś sprawdzić ten fakt za pomocą C #TimeSpan.TicksPerMillisecond
(powinno być 10000), aby się upewnić.Dzięki za radę. Ponieważ nie ma odpowiednika w serwerze SQL. Po prostu utworzyłem drugie pole, które przekształciło TimeSpan w tiki i zapisało je w DB. Następnie uniemożliwiłem przechowywanie TimeSpan
źródło
Jeśli nie musisz przechowywać więcej niż 24 godziny, możesz po prostu zapisać czas , ponieważ SQL Server 2008 i nowsze wersje są mapowane
time (SQL Server) <-> TimeSpan(.NET)
Nie potrzebujesz żadnych konwersji, jeśli potrzebujesz przechowywać tylko 24 godziny.
Źródło: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
Ale jeśli chcesz przechowywać więcej niż 24 godziny, musisz przechowywać je w tikach, pobierać dane, a następnie konwertować na TimeSpan. Na przykład
źródło
Time
nie ma reprezentować czasu trwania, ale część Time wartości DateTime; to okropny wybórTimeSpan
.Nie ma bezpośredniego odpowiednika. Po prostu przechowuj go numerycznie, np. Liczbę sekund lub coś odpowiedniego do wymaganej dokładności.
źródło
Wiem, że to stare pytanie, ale chciałem się upewnić, że odnotowano kilka innych opcji.
Ponieważ nie można przechowywać przedziału czasu większego niż 24 godziny w polu typu danych sql; może być kilka innych opcji.
Użyj varchar (xx) do przechowywania ToString TimeSpan. Zaletą tego jest to, że precyzja nie musi być zapisywana w typie danych ani w obliczeniach (sekundy vs milisekundy vs dni vs dwa tygodnie) Wystarczy użyć TimeSpan.Parse / TryParse. Tak bym zrobił.
Użyj drugiej daty, datetime lub datetimeoffset, która przechowuje wynik pierwszej daty + przedział czasu. Odczytywanie z db jest kwestią TimeSpan x = SecondDate - FirstDate. Użycie tej opcji ochroni Cię przed innymi bibliotekami dostępu do danych spoza platformy .NET, które mają dostęp do tych samych danych, ale nie rozumieją TimeSpans; jeśli masz takie środowisko.
źródło
Aby zachować spójność z prawdopodobnie najbardziej prawdopodobnym źródłem generowania przedziału czasu (obliczanie różnicy 2 razy lub daty i godziny), możesz przechowywać .NET
TimeSpan
jakoDateTime
typ SQL Server .Jest tak, ponieważ w programie SQL Server różnica 2
DateTime
(Cast
doFloat
, a następnie zCast
powrotem do aDateTime
) jest po prostuDateTime
względna w stosunku do 1 stycznia 1900 r. Np. Różnica wynosząca +0,1 sekundy to 1 stycznia 1900 00: 00: 00.100, a -0,1 sekundy to 31 grudnia 1899 23: 59: 59.900.Aby przekonwertować platformę .NET
TimeSpan
naDateTime
typ programu SQL Server , należy najpierw przekonwertować ją naDateTime
typ .NET , dodając ją do wersjiDateTime
z 1 stycznia 1900 r. Oczywiście po przeczytaniu jej .NET z programu SQL Server najpierw przeczytaj go w .NET,DateTime
a następnie odejmij od niego 1 stycznia 1900 r., aby przekonwertować go na .NETTimeSpan
.W przypadkach użycia, w których przedziały czasowe są generowane z SQL Server
DateTime
i SQL Server (tj. Przez T-SQL), a SQL Server jest wcześniejszy niż 2016, w zależności od zakresu i potrzeb w zakresie precyzji, przechowywanie ich może nie być praktyczne jako milisekundy (nie wspominając o tymTicks
), ponieważInt
typ zwracany przezDateDiff
(w porównaniuBigInt
z SS 2016+DateDiff_Big
) przepełnia się po ~ 24 dniach wartości milisekund i ~ 67 lat. sekund. Rozwiązanie to poradzi sobie z przedziałami czasu z dokładnością do 0,1 sekundy i od -147 do +8,099 lat.OSTRZEŻENIA:
Działałoby to tylko wtedy, gdy różnica w stosunku do 1 stycznia 1900 r.
DateTime
Dałaby wartość w zakresie typu SQL Server (od 1 stycznia 1753 r. Do 31 grudnia 9999 r., Aka -147 do +0899 lat). Nie musimy się tak bardzo martwić poTimeSpan
stronie .NET , ponieważ może pomieścić ~ 29 tys. Do +29 tys. Lat. Nie wspomniałem oDateTime2
typie serwera SQL (którego zakres, po ujemnej stronie, jest znacznie większy niż SQL ServerDateTime
), ponieważ: a) nie można go przekonwertować na liczbę za pomocą prostej,Cast
a b)DateTime
zakres powinien wystarczyć dla zdecydowanej większości przypadków użycia.SQL Server
DateTime
różnice obliczone za pośrednictwemCast
- do -Float
- i - metoda z powrotem nie wydaje się być dokładne niż 0,1 sekundy.źródło
Istnieje wiele sposobów prezentacji przedziału czasu w bazie danych.
czas
Ten typ danych jest obsługiwany od SQL Server 2008 i jest preferowanym sposobem przechowywania
TimeSpan
. Nie jest wymagane mapowanie. Działa również dobrze z kodem SQL.Jednak, jak stwierdzono w pierwotnym pytaniu, ten typ danych jest ograniczony do 24 godzin.
datetimeoffset
Typ
datetimeoffset
danych jest mapowany bezpośrednio naSystem.DateTimeOffset
. Służy do wyrażenia przesunięcia między adatetime
/datetime2
UTC, ale możesz go również użyć doTimeSpan
.Ponieważ jednak typ danych sugeruje bardzo specyficzny semantyczny, należy również rozważyć inne opcje.
datetime / datetime2
Jednym z podejść może być użycie
datetime
lubdatetime2
typów . Jest to najlepsze w scenariuszach, w których trzeba bezpośrednio przetwarzać wartości w bazie danych, tj. dla widoków, procedur przechowywanych lub raportów. Wadą jest to, że musisz odjąć wartośćDateTime(1900,01,01,00,00,00)
od daty, aby odzyskać czas w logice biznesowej.bigint
Innym podejściem może być konwersja TimeSpan na tiki i użycie
bigint
typu danych. Jednak takie podejście ma tę wadę, że uciążliwe jest stosowanie go w zapytaniach SQL.Varchar (N)
Jest to najlepsze w przypadkach, w których wartość powinna być czytelna dla ludzi. Możesz również użyć tego formatu w zapytaniach SQL, korzystając z
CONVERT(datetime, ValidityPeriod)
funkcji. W zależności od wymaganej precyzji potrzebujesz od 8 do 25 znaków.Bonus: okres i czas trwania
Za pomocą ciągu możesz także przechowywać typy danych NodaTime , zwłaszcza
Duration
iPeriod
. Pierwszy jest zasadniczo taki sam jak TimeSpan, natomiast później uwzględnia, że niektóre dni i miesiące są dłuższe lub krótsze niż inne (tj. Styczeń ma 31 dni, a luty 28 lub 29; niektóre dni są dłuższe lub krótsze z powodu czasu letniego ). W takich przypadkach użycie TimeSpan jest złym wyborem.Możesz użyć tego kodu do konwersji okresów:
A potem użyj go jak
naprawdę lubię
NodaTime
i często ratuje mnie przed trudnymi błędami i dużym bólem głowy. Wadą tego rozwiązania jest to, że tak naprawdę nie można go używać w zapytaniach SQL i trzeba wykonywać obliczenia w pamięci.Typ zdefiniowany przez użytkownika CLR
Możesz także użyć niestandardowego typu danych i bezpośrednio obsługiwać niestandardową
TimeSpan
klasę. Aby uzyskać szczegółowe informacje, zobacz Typy zdefiniowane przez użytkownika CLR .Wadą jest to, że typ danych może nie zachowywać się dobrze w przypadku raportów SQL. Ponadto niektóre wersje programu SQL Server (Azure, Linux, Data Warehouse) nie są obsługiwane.
Konwersje wartości
Począwszy od EntityFramework Core 2.1, masz możliwość użycia konwersji wartości .
Jednak podczas korzystania z tego EF nie będzie w stanie przekonwertować wielu zapytań na SQL, co spowoduje, że zapytania będą działać w pamięci; potencjalnie przesyłając wiele danych do aplikacji.
Przynajmniej na razie lepiej nie używać go i po prostu zmapować wynik zapytania za pomocą Automappera .
źródło
Zazwyczaj przechowuję TimeSpan jako bigint wypełniony kleszczami z właściwości TimeSpan.Ticks, jak wcześniej sugerowano. Możesz także zapisać TimeSpan jako varchar (26) wypełniony danymi wyjściowymi TimeSpan.ToString (). Cztery funkcje skalarne (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks), które napisałem, są pomocne w obsłudze TimeSpan po stronie SQL i unikają włamań, które spowodowałyby sztucznie ograniczone zakresy. Jeśli możesz przechowywać interwał w .NET TimeSpan, powinien on także działać z tymi funkcjami. Ponadto funkcje pozwalają na pracę z TimeSpans i 100-nanosekundowymi taktami, nawet przy użyciu technologii, które nie obejmują .NET Framework.
źródło