web-dev-qa-db-fra.com

Utilisation de DateTime dans un SqlParameter pour la procédure stockée, erreur de format

J'essaie d'appeler une procédure stockée (sur un serveur SQL 2005) à partir de C #, .NET 2.0 en utilisant DateTime comme valeur à un SqlParameter. Le type SQL dans la procédure stockée est "datetime".

L'exécution du sproc à partir de SQL Management Studio fonctionne correctement. Mais chaque fois que je l'appelle depuis C #, j'obtiens une erreur sur le format de la date.

Lorsque j'exécute SQL Profiler pour regarder les appels, je copie puis collez l'appel exec pour voir ce qui se passe. Voici mes observations et notes sur ce que j'ai tenté:

1) Si je passe le DateTime directement en tant que DateTime ou converti en SqlDateTime, le champ est entouré d'une PAIRE de guillemets simples, tels que

@Date_Of_Birth=N''1/8/2009 8:06:17 PM''

2) Si je passe le DateTime sous forme de chaîne, je ne reçois que les guillemets simples

3) L'utilisation de SqlDateTime.ToSqlString() n'entraîne pas une chaîne datetime au format UTC (même après la conversion en temps universel)

4) L'utilisation de DateTime.ToString() n'entraîne pas de chaîne de date/heure au format UTC.

5) La définition manuelle de DbType pour SqlParameter sur DateTime ne modifie pas les observations ci-dessus.

Donc, mes questions sont donc comment diable puis-je obtenir C # pour passer le temps correctement formaté dans le SqlParameter? C'est certainement un cas d'utilisation courant, pourquoi est-il si difficile de se mettre au travail? Je n'arrive pas à convertir DateTime en une chaîne compatible SQL (par exemple '2009-01-08T08: 22: 45')

MODIFIER

RE: BFree, le code pour exécuter réellement le sproc est le suivant:

using (SqlCommand sprocCommand = new SqlCommand(sprocName))
{
    sprocCommand.Connection = transaction.Connection;
    sprocCommand.Transaction = transaction;
    sprocCommand.CommandType = System.Data.CommandType.StoredProcedure;
    sprocCommand.Parameters.AddRange(parameters.ToArray());
    sprocCommand.ExecuteNonQuery();
}

Pour entrer plus en détail sur ce que j'ai essayé:

parameters.Add(new SqlParameter("@Date_Of_Birth", DOB));

parameters.Add(new SqlParameter("@Date_Of_Birth", DOB.ToUniversalTime()));

parameters.Add(new SqlParameter("@Date_Of_Birth", 
    DOB.ToUniversalTime().ToString()));

SqlParameter param = new SqlParameter("@Date_Of_Birth", 
    System.Data.SqlDbType.DateTime);
param.Value = DOB.ToUniversalTime();
parameters.Add(param);

SqlParameter param = new SqlParameter("@Date_Of_Birth", 
    SqlDbType.DateTime);
param.Value = new SqlDateTime(DOB.ToUniversalTime());
parameters.Add(param);

parameters.Add(new SqlParameter("@Date_Of_Birth", 
    new SqlDateTime(DOB.ToUniversalTime()).ToSqlString()));

EDIT supplémentaire

Celui que je pensais le plus susceptible de travailler:

SqlParameter param = new SqlParameter("@Date_Of_Birth",  
    System.Data.SqlDbType.DateTime);
param.Value = DOB;

Résultats dans cette valeur dans l'appel exec comme vu dans le SQL Profiler

@Date_Of_Birth=''2009-01-08 15:08:21:813''

Si je modifie ceci pour être:

@Date_Of_Birth='2009-01-08T15:08:21'

Cela fonctionne, mais il n'analysera pas avec une paire de guillemets simples, et il ne se convertira pas correctement en DateTime avec l'espace entre la date et l'heure et avec les millisecondes à la fin.

Mise à jour et succès

J'avais copié/collé le code ci-dessus après la demande d'en bas. J'ai coupé les choses ici et là pour être concis. Il s'avère que mon problème était dans le code que j'ai laissé de côté, que je suis sûr que n'importe lequel d'entre vous aurait repéré en un instant. J'avais enveloppé mes appels sproc dans une transaction. Il s'avère que je ne faisais tout simplement pas transaction.Commit() !!!!! J'ai honte de le dire, mais voilà.

Je ne sais toujours pas ce qui se passe avec la syntaxe que je récupère du profileur. Un collègue a regardé avec sa propre instance du profileur depuis son ordinateur, et cela a renvoyé la syntaxe appropriée. Regarder les exécutions mêmes de mon profileur a montré la syntaxe incorrecte. Il a agi comme un redingue, me faisant croire qu'il y avait un problème de syntaxe de requête au lieu de la réponse beaucoup plus simple et vraie, à savoir que je devais valider la transaction!

J'ai marqué une réponse ci-dessous comme correcte, et j'ai ajouté des votes positifs à d'autres parce qu'ils ont, après tout, répondu à la question, même s'ils n'ont pas résolu mon problème spécifique (défaillance du cerveau).

22
Matt

Comment configurez-vous le SqlParameter ? Vous devez définir la propriété SqlDbType sur SqlDbType.DateTime puis passez le DateTime directement au paramètre (ne PAS convertir en chaîne, vous demandez alors un tas de problèmes).

Vous devriez pouvoir obtenir la valeur dans la base de données. Sinon, voici un exemple très simple de comment le faire:

static void Main(string[] args)
{
    // Create the connection.
    using (SqlConnection connection = new SqlConnection(@"Data Source=..."))
    {
        // Open the connection.
        connection.Open();

        // Create the command.
        using (SqlCommand command = new SqlCommand("xsp_Test", connection))
        {
            // Set the command type.
            command.CommandType = System.Data.CommandType.StoredProcedure;

            // Add the parameter.
            SqlParameter parameter = command.Parameters.Add("@dt",
                System.Data.SqlDbType.DateTime);

            // Set the value.
            parameter.Value = DateTime.Now;

            // Make the call.
            command.ExecuteNonQuery();
        }
    }
}

Je pense qu'une partie du problème ici est que vous craignez que le fait que l'heure soit en UTC ne soit pas transmis à SQL Server. À cette fin, vous ne devriez pas, car SQL Server ne sait pas qu'une heure particulière est dans un lieu/fuseau horaire particulier.

Si vous souhaitez stocker la valeur UTC, puis convertissez-la en UTC avant de la transmettre à SQL Server (sauf si votre serveur a le même fuseau horaire que le code client générant le DateTime, et même dans ce cas, c'est un risque, OMI). SQL Server stockera cette valeur et lorsque vous la récupérerez, si vous voulez l'afficher à l'heure locale, vous devez le faire vous-même (ce que la structure DateTime fera facilement).

Cela étant dit, si vous effectuez la conversion, puis passez la date UTC convertie (la date qui est obtenue en appelant la méthode ToUniversalTime , pas en la convertissant en chaîne) à la procédure stockée.

Et lorsque vous récupérez la valeur, appelez la méthode ToLocalTime pour obtenir l'heure dans le fuseau horaire local.

29
casperOne

Voici comment j'ajoute des paramètres:

sprocCommand.Parameters.Add(New SqlParameter("@Date_Of_Birth",Data.SqlDbType.DateTime))
sprocCommand.Parameters("@Date_Of_Birth").Value = DOB

Je suppose que lorsque vous écrivez DOB, il n'y a pas de guillemets.

Utilisez-vous un contrôle tiers pour obtenir la date? J'ai eu des problèmes avec la façon dont la valeur du texte est générée à partir de certains d'entre eux.

Enfin, cela fonctionne-t-il si vous tapez l'attribut .Value du paramètre sans référencer DOB?

3
K Richard

Si tu utilises Microsoft.ApplicationBlocks.Data cela fera appeler vos sprocs une seule ligne

SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB)

Oh et je pense que casperOne est correct ... si vous voulez garantir la bonne date/heure sur plusieurs fuseaux horaires, convertissez simplement la valeur en UTC avant d'envoyer la valeur à SQL Server

SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB.ToUniversalTime())
0
Michael Prewecki

Utilisez simplement:

 param.AddWithValue("@Date_Of_Birth",DOB);

Cela prendra soin de tous vos problèmes.

0
BFree