J'essaie de stocker un .Net TimeSpan
dans SQL Server 2008 R2.
EF Code First semble suggérer qu'il devrait être stocké Time(7)
en SQL.
Cependant, TimeSpan
dans .Net, il peut gérer des périodes plus longues que 24 heures.
Quelle est la meilleure façon de gérer le stockage de .Net TimeSpan
dans le serveur SQL?
.net
sql-server
timespan
GraemeMiller
la source
la source
Réponses:
Je le stocke dans la base de données en tant que
BIGINT
et je stocke le nombre de graduations (par exemple, la propriété TimeSpan.Ticks ).De cette façon, si je voulais obtenir un objet TimeSpan lorsque je le récupère, je pourrais simplement faire TimeSpan.FromTicks (valeur), ce qui serait facile.
la source
SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME)
. La'1900-01-01'
date n'a pas d'importance, bien sûr, c'est juste la troisième variable requise par laDATEADD(...)
fonction. N'oubliez pas qu'il y a 100 nanosecondes dans une tique, mais si vous utilisez,DATEADD(NANOSECOND...
vous risquez d'obtenir un débordement, donc d'utiliser des millisecondes. N'oubliez pas que vous devez vérifier ce fait en utilisant C #TimeSpan.TicksPerMillisecond
(devrait être 10000) pour être sûr.Merci pour le conseil. Comme il n'y a pas d'équivalent dans SQL Server. J'ai simplement créé un 2ème champ qui a converti le TimeSpan en ticks et l'a stocké dans la base de données. J'ai ensuite empêché de stocker le TimeSpan
la source
Si vous n'avez pas à stocker plus de 24 heures, vous pouvez simplement stocker du temps , car SQL Server 2008 et versions ultérieures sont mappés
time (SQL Server) <-> TimeSpan(.NET)
Aucune conversion n'est nécessaire si vous ne devez stocker que 24 heures ou moins.
Source: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
Mais , si vous souhaitez stocker plus de 24h, vous devrez le stocker par ticks, récupérer les données puis les convertir en TimeSpan. Par exemple
la source
Time
type SQL n'est pas censé représenter une durée, mais la partie Time d'une valeur DateTime; c'est un choix terrible pourTimeSpan
.Il n'y a pas d'équivalent direct. Il suffit de le stocker numériquement, par exemple le nombre de secondes ou quelque chose de approprié à la précision requise.
la source
Je sais que c'est une vieille question, mais je voulais m'assurer que quelques autres options sont notées.
Étant donné que vous ne pouvez pas stocker un TimeSpan supérieur à 24 heures dans un champ de type de données time sql; quelques autres options pourraient être.
Utilisez un varchar (xx) pour stocker la ToString du TimeSpan. L'avantage de ceci est que la précision n'a pas à être intégrée dans le type de données ou le calcul, (secondes vs millisecondes vs jours vs quinzaines) Tout ce dont vous avez besoin est d'utiliser TimeSpan.Parse / TryParse. Voilà ce que je ferais.
Utilisez une deuxième date, datetime ou datetimeoffset, qui stocke le résultat de la première date + intervalle de temps. La lecture de la base de données est une question de TimeSpan x = SecondDate - FirstDate. L'utilisation de cette option vous protégera pour que d'autres bibliothèques d'accès aux données non .NET accèdent aux mêmes données mais ne comprennent pas les TimeSpans; au cas où vous auriez un tel environnement.
la source
Pour être cohérent avec ce qui est probablement la source la plus probable de génération d'un intervalle de temps (calcul de la différence de 2 fois ou date-heure), vous souhaiterez peut-être stocker un .NET en
TimeSpan
tant que type SQL ServerDateTime
.Cela est dû au fait que dans SQL Server, la différence de 2
DateTime
(Cast
àFloat
et puis deCast
nouveau à aDateTime
) est simplement unDateTime
relatif au 1er janvier 1900. Ex. Une différence de +0,1 seconde serait le 1er janvier 1900 00: 00: 00.100 et -0,1 seconde serait le 31 décembre 1899 23: 59: 59.900.Pour convertir un .NET
TimeSpan
en un type SQL ServerDateTime
, vous devez d'abord le convertir en unDateTime
type .NET en l'ajoutant auDateTime
1 janvier 1900. Bien sûr, lorsque vous le lisez dans .NET à partir de SQL Server, vous devez d'abord lisez-le dans un .NETDateTime
puis soustrayez-le le 1er janvier 1900 pour le convertir en .NETTimeSpan
.Pour les cas d'utilisation où les intervalles de temps sont générés à partir de SQL Server
DateTime
et dans SQL Server (c'est-à-dire via T-SQL) et SQL Server est antérieur à 2016, selon votre plage et vos besoins de précision, il peut ne pas être pratique de les stocker en millisecondes (sans parlerTicks
) car leInt
type renvoyé parDateDiff
( par rapport auxBigInt
SS 2016+DateDiff_Big
) déborde après environ 24 jours de millisecondes et ~ 67 ans. de secondes. Considérant que, cette solution gérera les intervalles de temps avec précision jusqu'à 0,1 seconde et de -147 à +8 099 ans.AVERTISSEMENTS:
Cela ne fonctionnerait que si la différence par rapport au 1er janvier 1900 se traduisait par une valeur dans la plage d'un type SQL Server
DateTime
(du 1er janvier 1753 au 31 décembre 9999 aka -147 à +8 099 ans). Nous n'avons pas à nous inquiéter autant duTimeSpan
côté .NET , car il peut contenir de ~ 29 k à +29 k ans. Je n'ai pas mentionné le type SQL ServerDateTime2
(dont la plage, du côté négatif, est beaucoup plus grande que celle de SQL ServerDateTime
), car: a) il ne peut pas être converti en numérique via un simpleCast
et b)DateTime
la plage devrait suffire pour la grande majorité des cas d'utilisation.SQL Server
DateTime
différences calculées par leCast
- à -Float
- et - méthode de retour ne semble pas être précis au - delà de 0,1 seconde.la source
Il existe plusieurs façons de présenter un intervalle de temps dans la base de données.
temps
Ce type de données est pris en charge depuis SQL Server 2008 et est le moyen préféré de stocker un fichier
TimeSpan
. Aucun mappage n'est nécessaire. Il fonctionne également bien avec le code SQL.Cependant, comme indiqué dans la question d'origine, ce type de données est limité à 24 heures.
datetimeoffset
Le
datetimeoffset
type de données correspond directement àSystem.DateTimeOffset
. Il est utilisé pour exprimer le décalage entre undatetime
/datetime2
vers UTC, mais vous pouvez également l'utiliser pourTimeSpan
.Cependant, puisque le type de données suggère une sémantique très spécifique, vous devriez donc également envisager d'autres options.
datetime / datetime2
Une approche pourrait consister à utiliser les types
datetime
oudatetime2
. C'est le meilleur dans les scénarios où vous devez traiter directement les valeurs dans la base de données, c'est-à-dire. pour les vues, les procédures stockées ou les rapports. L'inconvénient est que vous devez soustraire la valeurDateTime(1900,01,01,00,00,00)
de la date pour récupérer l'intervalle de temps dans votre logique métier.bigint
Une autre approche pourrait être de convertir le TimeSpan en ticks et d'utiliser le
bigint
type de données. Cependant, cette approche présente l'inconvénient d'être lourde à utiliser dans les requêtes SQL.varchar (N)
Ceci est préférable dans les cas où la valeur doit être lisible par l'homme. Vous pouvez également utiliser ce format dans les requêtes SQL en utilisant la
CONVERT(datetime, ValidityPeriod)
fonction. En fonction de la précision requise, vous aurez besoin de 8 à 25 caractères.Bonus: période et durée
À l'aide d'une chaîne, vous pouvez également stocker des types de données NodaTime , en particulier
Duration
etPeriod
. Le premier est fondamentalement le même qu'un TimeSpan, tandis que le dernier respecte le fait que certains jours et mois sont plus longs ou plus courts que d'autres (c.-à-d. Janvier a 31 jours et février en a 28 ou 29; certains jours sont plus longs ou plus courts en raison de l'heure d'été) ). Dans de tels cas, l'utilisation d'un TimeSpan n'est pas le bon choix.Vous pouvez utiliser ce code pour convertir des périodes:
Et puis utilisez-le comme
J'aime vraiment
NodaTime
et cela m'évite souvent des bugs délicats et beaucoup de maux de tête. L'inconvénient ici est que vous ne pouvez vraiment pas l'utiliser dans les requêtes SQL et devez faire des calculs en mémoire.Type défini par l'utilisateur CLR
Vous avez également la possibilité d'utiliser un type de données personnalisé et de prendre en charge
TimeSpan
directement une classe personnalisée . Voir Types définis par l'utilisateur CLR pour plus de détails.L'inconvénient ici est que le type de données peut ne pas bien se comporter avec les rapports SQL. De plus, certaines versions de SQL Server (Azure, Linux, Data Warehouse) ne sont pas prises en charge.
Conversions de valeur
À partir d'EntityFramework Core 2.1, vous avez la possibilité d'utiliser des conversions de valeur .
Cependant, lors de l'utilisation de cela, EF ne sera pas en mesure de convertir de nombreuses requêtes en SQL, provoquant l'exécution des requêtes en mémoire; en transférant potentiellement beaucoup et beaucoup de données vers votre application.
Donc, au moins pour l'instant, il serait préférable de ne pas l'utiliser et de simplement mapper le résultat de la requête avec Automapper .
la source
En règle générale, je stocke un TimeSpan en tant que bigint rempli de graduations de la propriété TimeSpan.Ticks comme suggéré précédemment. Vous pouvez également stocker un TimeSpan en tant que varchar (26) rempli avec la sortie de TimeSpan.ToString (). Les quatre fonctions scalaires (ConvertFromTimeSpanString, ConvertToTimeSpanString, DateAddTicks, DateDiffTicks) que j'ai écrites sont utiles pour gérer TimeSpan du côté SQL et éviter les hacks qui produiraient des plages limitées artificiellement. Si vous pouvez stocker l'intervalle dans un TimeSpan .NET, cela devrait également fonctionner avec ces fonctions. De plus, les fonctions vous permettent de travailler avec des TimeSpans et des ticks de 100 nanosecondes même lorsque vous utilisez des technologies qui n'incluent pas le .NET Framework.
la source