2014-01-28 1 views
1

Может ли кто-нибудь сказать мне, что происходит в этой функции? В следующем фрагменте кода, user.Id = 0, id.Value = 0 и id.SqlDbType = Int .. как ожидается, начиная с user.Id is int field.Конструктор .NET SqlParameter несовместим?

Однако error.Value = null и error.SqlDbType = BigInt. Что дает? Если я использую ненулевое значение, он обнаруживает значение int и правильное значение.

Примечание: свойства Value одинаковы до и после объявления направления параметра.

public static long InsertUpdate(User user) { 

    SqlParameter id = new SqlParameter("@id", user.Id); 
    id.Direction = ParameterDirection.InputOutput; 
    cmd.Parameters.Add(id); 

    SqlParameter error = new SqlParameter("@error_code", 0); 
    error.Direction = ParameterDirection.Output; 
    cmd.Parameters.Add(error); 

    .... other stuff 
} 

Как хорошо, если @SET @error_Code = 0 в sproc, error.Value = NULL, и error.SqlDbType = NVARCHAR после процедуры проходит. Если я устанавливаю его в целое число, я получаю тип Int.

UPDATE: После указания SqlDbType.Int параметр теперь имеет правильный SqlDbType до и после команды ... Однако хранимая процедура еще установка @error_code = нуль, когда я на самом деле установить его в 0.

UPDATE: когда sproc выполняет ЗЕЬЕСТ параметр @error_code всегда возвращается как нуль, независимо от того, когда и не было установлено ... это происходит только тогда, когда есть оператор выбора ...

Вот процедура для воспроизведения:

ALTER PROCEDURE [dbo].[usp_user_insert_v1] 
    @username VARCHAR(255), 
    @password VARCHAR(255), 
    @gender CHAR(1), 
    @birthday DATETIME, 
    @error_code INT OUTPUT 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @default_dt DATETIME 
    EXEC @default_dt = uf_get_default_date 
    DECLARE @dt DATETIME = GETUTCDATE() 

      INSERT INTO users(username, password, gender, birthday, create_dt, last_login_dt, update_dt, deleted) 
      VALUES(@username, @password, @gender, @birthday, @dt, @default_dt, @default_dt, 0) 
      SELECT * FROM users WHERE id = SCOPE_IDENTITY() 
      SET @error_code = 3 
      RETURN 

END 

РЕШЕНИЕ?

http://forums.asp.net/t/1208409.aspx?Interesting+problem+with+getting+OUTPUT+parameters+from+SQL+Server+using+C+

Найдено эту ссылку на форумах ASP ... видимо вы не можете прочитать выходной параметр, пока не прочитал все результаты от SqlDataReader ... очень печально для меня, так как я решаю даже ли или нет я хочу, чтобы читать результаты на основании выходного сигнала парам ...

ответ

1

Оба текущих ответов немного неправильно, потому что они основаны на предположении, что конструктор будет вызван для error объекта является (string,object) один. Это не тот случай. Литерал 0 может быть преобразован в любой тип перечисления , и такое преобразование было бы предпочтительным по сравнению с преобразованием в object. Таким образом, вызываемый конструктор представляет собой конструктор (string,SqlDbType).

Так тип установлен BigInt, потому что это значение 0 для SqlDbType перечисления, а Value равно нулю, потому что у вас нет кода, который пытается установить значение.

SqlParameter error = new SqlParameter("@error_code", (object)0); 

должно привести к правильной перегрузке.


Демонстрация:

using System; 
using System.Data; 

namespace ConsoleApplication 
{ 
    internal class Program 
    { 
     private static void Main() 
     { 
      var a = new ABC("ignore", 0); 
      var b = new ABC("ignore", (object)0); 
      var c = new ABC("ignore", 1); 
      int i = 0; 
      var d = new ABC("ignore", i); 
      Console.ReadLine(); 
     } 

    } 

    public class ABC 
    { 
     public ABC(string ignore, object value) 
     { 
      Console.WriteLine("Object"); 
     } 

     public ABC(string ignore, SqlDbType value) 
     { 
      Console.WriteLine("SqlDbType"); 
     } 
    } 
} 

Печать:

SqlDbType 
Object 
Object 
Object 

Из C# Language specification, version 5, раздел 1.10 (то есть, только в введении на язык, не захоронены глубоко в язык lawyery бит):

Для того, чтобы значение по умолчанию типа перечислений, чтобы быть легко доступны, буквальный 0 неявно преобразуется в любой тип перечисления. Таким образом, допускается следующее.

Color c = 0; 

Я также думал, что это достаточно важно, чтобы быть в Language Reference на MSDN, но не нашли окончательного источника еще.

+0

Можете ли вы объяснить, почему SqlParamter («@ id», user.Id) создает Int, а не SqlParameter («@ error_code», 0)? user.Id - это поле int, установленное в 0. Кроме того, SqlParamter («@ error_code», 2) правильно создает устанавливает SqlDataParamter в int ... поэтому я не думаю, что он выбирает конструктор SqlDataType (name, SqlDbType) когда передается целочисленный литерал. – Cailen

+0

'user.Id' не является целым ** литералом ** при любых обстоятельствах. И это целочисленный литерал '0', который имеет этот специальный случай, который позволяет преобразовать его в значение« enum ». И, если вы мне не верите, попробуйте добавить больше примеров к образцу кода, который я включил в свой ответ, который я сделал, чтобы вы могли * видеть *, какая перегрузка выбрана для разных обстоятельств. –

+0

Извините, буквальное было совершенно неправильным словом. Я вижу вашу точку зрения, странно, что другие целочисленные литералы не интерпретируются как перечисления SqlDbType. – Cailen

0

Ну, это выглядит как самый надежный способ сделать это состоит в использовании this overload:

SqlParameter error = new SqlParameter("@error_code", SqlDBType.Int); 
error.Value = 0; 

Перегрузка, которую вы используете, принимает параметр object как параметр, и по какой-то причине, которую я не могу божественно, он не выбирает правильный тип.

+0

Компилятор предпочтет преобразовать '0' в тип перечисления, чем преобразовать его в' object'. –

2

От SqlParameter.Value on MSDN

Для выходных и возвращаемых значений параметров, значение устанавливается по завершении SqlCommand

т.е. я бы не полагаться на умозаключения типа, чтобы установить тип возвращаемого значения неявно. я бы точно установить тип выходного параметра:

var error = new SqlParameter("@error_code", SqlDbType.Int) 
{ 
    Direction = ParameterDirection.Output 
}; 

Редактировать

После некоторого отражения SqlParameter:

BigInt легко объяснить - это по умолчанию SqlDbType и SqlParameter(string parameterName, object value) ctor не перезаписывает это значение.

public enum SqlDbType 
{ 
    BigInt = 0, 
    ... 

Re: @error_code возвращается как NULL

Единственное, что я могу думать о том, что PROC не выполняет чисто. Попробуйте переместить SET @error_code = 0 выше EXEC @default_dt = uf_get_default_date?

Редактировать

Подтверждено, @ точка Дамьена является правильным

SqlParameter error = new SqlParameter("@error_code", 0); 

На самом деле называет это CTOR:

public SqlParameter(string parameterName, SqlDbType dbType) 

, тогда как

SqlParameter error = new SqlParameter("@error_code", 1234); 

звонков

public SqlParameter(string parameterName, object value) 

Причина: 0 is implicitly castable to enum.

+0

Возможно, это должен быть другой вопрос, но знаете ли вы, почему SqlDbType является NVarChar, когда моя процедура sql объявляет '@error_code INT OUTPUT' и делает SET '@error_code = 0' в начале процедуры? Похоже, он должен ПОЛНОСТЬЮ устанавливать его в нужный тип данных после выполнения команды в соответствии с вашей ссылкой. – Cailen

+0

@Cailen updated - dotPeeked 'SqlParameter'. – StuartLC

+0

Перейти к новому вопросу о том, почему мой выходной параметр обнуляется в sproc (я это проверил, когда в процедуре выполняется инструкция SELECT, а выходной параметр получает значение null, независимо от 0 или ненулевого). Def +1 для напоминания об инициализаторах объектов. – Cailen

 Смежные вопросы

  • Нет связанных вопросов^_^