236 votes

Quel est le type SQL correct pour stocker un timespan .Net avec des valeurs > 24:00:00 ?

J'essaie de stocker un fichier .Net TimeSpan dans le serveur SQL 2008 R2.

EF Code First semble suggérer qu'il devrait être stocké en tant que Time(7) en SQL.

Cependant TimeSpan en .Net peut gérer des périodes plus longues que 24 heures.

Quelle est la meilleure façon de gérer le stockage des fichiers .Net. TimeSpan dans le serveur SQL ?

15 votes

Je l'utilise pour stocker la durée des événements récurrents. Je voulais donc capturer la durée de l'événement indépendamment de la date.

0 votes

1 votes

Relié, pas en double. J'ai écrit les deux. L'un concerne le Code First et la manière de modifier le mappage pour TimeSpan. L'autre porte sur le mappage de TimeSpan de type .Net à SQL.

256voto

Tom Chantler Points 8266

Je le stocke dans la base de données en tant que BIGINT et je stocke le nombre de ticks (ex. TimeSpan.Ticks propriété).

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.

3 votes

Comment gérer les calculs en sql, si vous avez besoin de calculer le nombre d'heures qu'il contient ?

11 votes

Je convertirais probablement les ticks en un objet temps comme ceci : SELECT CAST(DATEADD(MILLISECOND, @Ticks/CAST(10000 AS BIGINT), '1900-01-01') AS TIME) . Le site '1900-01-01' La date n'a pas d'importance, bien sûr, c'est juste la troisième variable requise par le programme DATEADD(...) fonction. Rappelez-vous qu'il y a 100 nanosecondes dans un tick, mais si vous utilisez la fonction DATEADD(NANOSECOND... vous risquez d'obtenir un dépassement, d'où l'utilisation des millisecondes. Rappelez-vous également que vous devez vérifier ce fait en utilisant C# TimeSpan.TicksPerMillisecond (devrait être 10000) pour être sûr.

0 votes

Une option est de le stocker sous forme de chaîne de caractères, vous pouvez ensuite le charger en utilisant TimeSpan.Parse(text). Ce n'est pas idéal du point de vue de la taille ou des requêtes SQL, mais il peut être analysé dans TSQL si nécessaire.

68voto

GraemeMiller Points 4299

Merci pour le conseil. Comme il n'y a pas d'équivalent dans le serveur SQL. J'ai simplement créé un second champ qui convertit le TimeSpan en ticks et le stocke dans la base de données. J'ai ensuite empêché le stockage du TimeSpan

public Int64 ValidityPeriodTicks { get; set; }

[NotMapped]
public TimeSpan ValidityPeriod
{
    get { return TimeSpan.FromTicks(ValidityPeriodTicks); }
    set { ValidityPeriodTicks = value.Ticks; }
}

9 votes

Pour ceux qui utilisent EF Core, la version 2.1 permet d'utiliser les conversions de valeurs et TimeSpanToTicksConverter pour convertir de manière transparente les intervalles de temps en ticks dans la base de données.

36voto

Si vous n'avez pas besoin de stocker plus de 24 heures, vous pouvez juste stocker temps Depuis SQL Server 2008 et les versions ultérieures, le mappage est le suivant

time (SQL Server) <-> TimeSpan(.NET)

Aucune conversion n'est nécessaire si vous n'avez besoin de stocker que 24 heures ou moins.

Fuente: http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx

Mais Si vous voulez stocker plus de 24 heures, vous devrez les stocker en ticks, récupérer les données et les convertir en TimeSpan. Par exemple

int timeData = yourContext.yourTable.FirstOrDefault();
TimeSpan ts = TimeSpan.FromMilliseconds(timeData);

24 votes

Comme le dit l'OP, le DataType "time" dans SQL Server ne supporte que jusqu'à 24h, il veut stocker > 24h.

11 votes

De même, TimeSpan (.NET) peut être négatif alors que Time (SQL Server) ne le peut pas.

13 votes

Il existe une différence majeure entre un temps et une durée. L'heure représente le temps d'un certain jour alors que la durée est la différence entre deux moments. Comparez-les à un lieu (temps) et à une distance (durée).

20voto

fearofawhackplanet Points 12147

Il n'y a pas d'équivalent direct. Il suffit de le stocker numériquement, par exemple en nombre de secondes ou quelque chose d'approprié à la précision requise.

0 votes

Par exemple, stockez-le sous forme de flottant et utilisez ` TimeSpan.FromSeconds` comme indiqué dans le tableau ci-dessous. msdn.microsoft.com/fr/us/library/

11voto

MovGP0 Points 77

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 supporté depuis SQL Server 2008 et est le méthode préférée pour stocker un TimeSpan . Aucun mappage n'est nécessaire. Il fonctionne également bien avec le code SQL.

public TimeSpan ValidityPeriod { get; set; }

Toutefois, comme indiqué dans la question initiale, ce type de données est limité à 24 heures.

datetimeoffset

El datetimeoffset correspond directement au type de données System.DateTimeOffset . Il est utilisé pour exprimer le décalage entre un datetime / datetime2 à UTC, mais vous pouvez également l'utiliser pour TimeSpan .

Toutefois, comme le type de données suggère une sémantique très spécifique, vous devez également envisager d'autres options.

datetime / datetime2

Une approche pourrait consister à utiliser le datetime o datetime2 types. C'est la meilleure solution dans les scénarios où vous devez traiter les valeurs dans la base de données directement, c'est-à-dire pour les vues, les procédures stockées ou les rapports. L'inconvénient est que vous devez soustraire la valeur DateTime(1900,01,01,00,00,00) de la date pour récupérer la période de temps dans votre logique d'entreprise.

public DateTime ValidityPeriod { get; set; }

[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
    get { return ValidityPeriod - DateTime(1900,01,01,00,00,00); }
    set { ValidityPeriod = DateTime(1900,01,01,00,00,00) + value; }
}

bigint

Une autre approche pourrait consister à convertir le TimeSpan en ticks et à utiliser la fonction bigint type de données. Toutefois, cette approche présente l'inconvénient d'être lourde à utiliser dans les requêtes SQL.

public long ValidityPeriod { get; set; }

[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
    get { return TimeSpan.FromTicks(ValidityPeriod); }
    set { ValidityPeriod = value.Ticks; }
}

varchar(N)

Ce format est le meilleur pour les cas où la valeur doit être lisible par les humains. Vous pouvez également utiliser ce format dans les requêtes SQL en utilisant l'attribut CONVERT(datetime, ValidityPeriod) fonction. En fonction de la précision requise, vous aurez besoin de 8 à 25 caractères.

public string ValidityPeriod { get; set; }

[NotMapped]
public TimeSpan ValidityPeriodTimeSpan
{
    get { return TimeSpan.Parse(ValidityPeriod); }
    set { ValidityPeriod = value.ToString("HH:mm:ss"); }
}

Bonus : Période et durée

En utilisant une chaîne, vous pouvez également stocker NodaTime les types de données, en particulier Duration y Period . Le premier est fondamentalement identique à un TimeSpan, tandis que le second respecte le fait que certains jours et mois sont plus longs ou plus courts que d'autres (par exemple, le mois de janvier compte 31 jours et celui de février 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 est le mauvais choix.

Vous pouvez utiliser ce code pour convertir les périodes :

using NodaTime;
using NodaTime.Serialization.JsonNet;

internal static class PeriodExtensions
{
    public static Period ToPeriod(this string input)
    {
        var js = JsonSerializer.Create(new JsonSerializerSettings());
        js.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
        var quoted = string.Concat(@"""", input, @"""");
        return js.Deserialize<Period>(new JsonTextReader(new StringReader(quoted)));
    }
}

Et ensuite l'utiliser comme

public string ValidityPeriod { get; set; }

[NotMapped]
public Period ValidityPeriodPeriod
{
    get => ValidityPeriod.ToPeriod();
    set => ValidityPeriod = value.ToString();
}

J'aime vraiment NodaTime et cela m'évite souvent des bugs délicats et beaucoup de maux de tête. L'inconvénient est que vous ne pouvez pas vraiment l'utiliser dans des requêtes SQL et que vous devez effectuer des calculs en mémoire.

CLR Type défini par l'utilisateur

Vous avez également la possibilité d'utiliser un type de données personnalisé et de prendre en charge un modèle de données personnalisé. TimeSpan directement. Voir Types définis par l'utilisateur dans le CLR pour les détails.

L'inconvénient ici est que le type de données peut ne pas se comporter correctement avec les rapports SQL. En outre, certaines versions de SQL Server (Azure, Linux, Data Warehouse) ne sont pas prises en charge.

Conversions de valeurs

À partir de EntityFramework Core 2.1, vous avez la possibilité d'utiliser Conversions de valeurs .

Cependant, en l'utilisant, EF ne sera pas en mesure de convertir de nombreuses requêtes en SQL, ce qui permet aux requêtes de s'exécuter en mémoire et de transférer potentiellement de très nombreuses données vers votre application.

Donc, au moins pour l'instant, il est préférable de ne pas l'utiliser, et de simplement faire correspondre le résultat de la requête avec Automapper .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X