2009-01-08 12 views
21

Próbuję wywołać procedurę przechowywaną (na serwerze SQL 2005) z C#, .NET 2.0 przy użyciu DateTime jako wartość do SqlParameter. Typ SQL w procedurze przechowywanej to "datetime".Korzystanie z DateTime w SqlParameter dla procedury składowanej, błąd formatu

Wykonywanie sproc z SQL Management Studio działa dobrze. Ale za każdym razem, gdy nazywam to C#, pojawia się błąd dotyczący formatu daty.

Po uruchomieniu programu SQL Profiler, aby obejrzeć połączenia, kopiuję wklej połączenie exec, aby sprawdzić, co się dzieje. To są moje spostrzeżenia i uwagi na temat tego, co już próbowali:

1) Jeżeli Mijam DateTime bezpośrednio jako DateTime lub przekształca się SqlDateTime pole otacza przez parę apostrofami, takich jak

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

2) Jeżeli mijam DateTime w postaci ciągu znaków, mam tylko pojedyncze cytaty

3) przy użyciu SqlDateTime.ToSqlString() nie spowodować UTC sformatowany ciąg datetime (nawet po konwersji do czasu uniwersalnego)

4) Użycie numeru DateTime.ToString() nie powoduje sformatowanego ciągu datetime w formacie UTC.

5) Ręczne ustawienie DbType dla SqlParameter na nie zmienia powyższych obserwacji.

Tak, więc moje pytania brzmią: w jaki sposób mogę uzyskać C#, by przekazać odpowiednio sformatowany czas w SqlParameter? Z pewnością jest to powszechny przypadek użycia, dlaczego tak trudno jest pracować? I nie wydaje się, aby przekształcić DateTime do łańcucha, który jest SQL kompatybilne (np '2009-01-08T08: 22: 45')

EDIT

RE: BFree, kod faktycznie wykonanie europejskiego sproc jest następujący:

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(); 
} 

Aby przejść do bardziej szczegółowo o tym, co próbowałem:

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())); 

Dodatkowe EDIT

Jeden myślałem najprawdopodobniej do pracy:

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

wyniki w tej wartości w exec wywołania jak widać w SQL Profiler

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

Gdybym zmodyfikować to do być:

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

Działa, ale nie będzie parsować z parą śpiewać le cytuje i nie zostanie poprawnie przekonwertowany na DateTime z odstępem między datą i czasem oraz z milisekundami na końcu.

Update i Sukces

miałem kopiowania/wklejania powyższy kod po żądaniu od dołu. Przycinałem rzeczy tu i tam, by były zwięzłe. Okazuje się, że mój problem tkwił w kodzie, który pominąłam, co jestem pewien, że ktokolwiek z was zauważyłby w mgnieniu oka. Zawarłem moje sprocowe wywołania wewnątrz transakcji. Okazuje się, że po prostu nie robiłem transaction.Commit() !!!!! Wstydzę się tego mówić, ale tam to masz.

Nadal nie wiem, co się dzieje ze składnią, którą wracam z profilera. Współpracownik obserwował z własnej instancji profilera ze swojego komputera i zwrócił poprawną składnię. Oglądanie bardzo SAME egzekucji z mojego profilera pokazało niepoprawną składnię. Działał jak czerwony śledzia, co sprawiło, że wierzyłem, że istnieje problem z składnią zapytań zamiast o wiele prostszą i prawdziwszą odpowiedzią, która polegała na tym, że muszę dokonać transakcji!

Odpowiednio oznaczyłem poniższą odpowiedź i wrzuciłem kilka głosów do góry, ponieważ w końcu udzieliły odpowiedzi na to pytanie, nawet jeśli nie rozwiązały mojego konkretnego problemu (problem z upływem czasu).

Odpowiedz

24

W jaki sposób konfigurujesz SqlParameter? Powinieneś ustawić SqlDbType property na SqlDbType.DateTime, a następnie przekazać DateTime bezpośrednio do parametru (NIE konwertować na ciąg znaków, dlatego pytasz o kilka problemów).

Powinieneś być w stanie uzyskać wartość do DB. Jeśli nie, tutaj jest bardzo prosty przykład jak to zrobić:

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(); 
     } 
    } 
} 

myślę częścią problemu jest to, że martwisz się, że fakt, że czas jest w UTC nie jest przekazywana do programu SQL Server . W tym celu nie powinieneś, ponieważ SQL Server nie wie, że konkretny czas jest w określonej strefie/strefie czasowej.

Jeśli chcesz zapisać wartość UTC, przekonwertuj ją na UTC przed przekazaniem do serwera SQL Server (chyba że twój serwer ma tę samą strefę czasową co kod klienta generujący DateTime, a nawet wtedy, to jest ryzyko, IMO). SQL Server zapisze tę wartość, a kiedy ją odzyskasz, jeśli chcesz wyświetlić ją w czasie lokalnym, musisz to zrobić samodzielnie (co łatwo może zrobić struktura DateTime).

Wszystko, co jest powiedziane, jeśli wykonujesz konwersję, a następnie przekazujesz skonwertowaną datę UTC (datę uzyskaną przez wywołanie ToUniversalTime method, a nie przez konwersję na ciąg) do procedury składowanej.

Po otrzymaniu wartości należy zadzwonić pod numer ToLocalTime method, aby uzyskać czas w lokalnej strefie czasowej.

0

Wystarczy użyć:

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

To zajmie się wszystkimi swoimi problemami.

+0

nie wydaje się pracować - za SQL Profiler, format ciągu jest nieprawidłowe, a jeśli mogę skopiować pasty, para apostrofami z każdej strony nie jest ważne albo – Matt

2

Oto jak dodać parametry:

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

jestem zakładając, kiedy pisać DOB nie ma żadnych cytatów.

Czy używasz kontrolki innej firmy, aby uzyskać datę? Miałem problemy ze sposobem generowania wartości tekstowej z niektórych z nich.

Wreszcie, działa, jeśli wpiszesz atrybut .Value parametru bez odniesienia DOB?

0

Jeśli używasz Microsoft.ApplicationBlocks.Data będzie to zrobić dzwoniąc do sprocs pojedynczą linię

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

No i myślę casperOne jest prawidłowa ... jeśli chcesz, aby zapewnić prawidłowy datetime na wiele stref czasowych po prostu przekonwertować wartość UTC zanim wyślesz wartość SQL Server

SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB.ToUniversalTime()) 
Powiązane problemy