2014-10-31 17 views
1

我有一個存儲過程需要3個參數,第一個和第二個參數的類型爲varchar,最後一個是用戶定義的表類型。用戶定義表類型(UDTT)參數是否可以與其他類型混合

當我通過ExecuteNonQuery EXEC存儲過程,它拋出異常:

[System.Data.SqlClient.SqlException] = { 「操作數類型衝突:nvarchar的是與ttOrderItems不相容」}

ttOrderItems是用戶定義的表類型。

這種行爲是否正常?當其中一個參數是用戶定義表類型時,它不會混合使用參數?

下面是調用存儲過程的代碼片段:

public DataSet execProc(string storedProcedureName, IDictionary<string, object> prms = null) 
     { 
      using (SqlCommand cmd = new SqlCommand(storedProcedureName, scon)) 
      { 
       DataSet rs = new DataSet(); 
       if (prms != null) SetupParams(storedProcedureName, cmd, prms); 
       try 
       { 
        cmd.CommandText = storedProcedureName; 
        cmd.CommandType = CommandType.StoredProcedure; 
        cmd.Connection.Open(); 
        //using (SqlDataAdapter da = new SqlDataAdapter(cmd)) da.Fill(rs); 
        //{ 
        // da.Fill(rs); 
        //} 
        cmd.ExecuteNonQuery(); 
        cmd.Connection.Close(); 
         return rs; 
       } 
       catch (Exception ex) 
       { 
        throw ex; 
       } 
       finally 
       { 
        scon.Close(); 
       } 
      } 
     } 

private void SetupParams(string RoutineName, SqlCommand cmd, IDictionary<string, object> prms, bool keepConnectionOpen = true) 
     { 
      if (cmd != null) cmd.Parameters.Clear(); 
      string pname = ""; 
      DataTable tblParams = Select("Select * from dbo.ftRoutineSchema('" + RoutineName + "')"); 
      foreach (DataRow dr in tblParams.Rows) 
      { 
       System.Data.SqlClient.SqlParameter p = new System.Data.SqlClient.SqlParameter(); 
       pname = dr["COLUMnNAME"].ToString().ToLower(); 
       p.ParameterName = pname; 
       pname = pname.Remove(0, 1).ToLower(); // remove @ sign 
       if (prms.Keys.Contains(pname)) p.Value = prms[pname]; 
       string direction = dr["Direction"].ToString().ToLower(); 
       string sptype = (string)dr["DataType"]; 
       string[] sx = dr["DataType"].ToString().Split(new char[] { '(', ',', ')' }); 
       try 
       { 
        #region case type switch 
        switch (sx[0].ToLower()) 
        { 
         case "int": 
          p.DbType = DbType.Int32;//=int.Parse(sx[2]); 
          break; 
         case "bigint": 
          p.DbType = DbType.Int64; 
          break; 
         case "varchar": 
          p.DbType = DbType.String; 
          p.Size = int.Parse(sx[1]); 
          break; 
         case "nvarchar": 
          p.DbType = DbType.String; 
          p.Size = int.Parse(sx[1]); 
          break; 
         case "decimal": 
          p.DbType = DbType.Decimal; 
          break; 
         case "datetime": 
          p.DbType = DbType.DateTime; 
          break; 
         case "ntext": 
         case "text": 
          p.DbType = DbType.String; 
          p.Size = 65536; 
          break; 

         default: 
          break; 
        } 
        switch (direction) 
        { 
         case "in": p.Direction = ParameterDirection.Input; break; 
         case "out": p.Direction = ParameterDirection.Output; break; 
         case "rc": p.Direction = ParameterDirection.ReturnValue; break; 
         default: break; 
        } 
        #endregion 
        if (sx[0] == "table type") 
        { 
         p.SqlDbType = SqlDbType.Structured; 

         cmd.Parameters.AddWithValue(p.ParameterName, p.Value.ToString()); 
        } 
        else 
         cmd.Parameters.Add(p); 
       } 

       catch (Exception ex) 
       { 
        throw ex; 
       } 
      } 
     } 

當我exec的通過下面的T-SQL一樣PROC,它按預期工作:

use edi 
go 
declare @items dbo.ttOrderItems 
insert @items 
      select 1,'574114-023',1,'EA',720,'2014-Oct-14',null,null 
union all select 2,'574116-035',8,'EA',1865.5,'2014-Oct-10',null,null 
exec dbo.prCatalogItems '010','000164',@items 

CREATE function [dbo].[ftCatalogItems](@comno varchar(3),@cuno varchar(6),@items ttOrderItems readonly) returns table as 
    /*------------------------------------------------------- 
    DECLARE @COMNO VARCHAR(3)='010',@CUNO VARCHAR(6)='000164' 
    declare @items ttOrderItems; 
    insert @items(position,ItemCode  ,QtyOrdered ,UOM ,PriceQuoted,RequiredBy  ,ExpectedOnDock ,BackOrdered) 
    select        1,'1231-221' ,1     ,'EA' ,20.20   ,'2014-11-01' ,'2014-11-01'  ,0 
    union select     2,'110223-245',10     ,'EA' ,2001.20  ,'2014-11-01' ,'2014-11-01'  ,0 


    select * from @items 
    --------------------------------------------------------*/ 
    return(

    select 
       Position 
       ,ItemCode 
       ,QtyOrdered 
       ,'EA' UOM 
      ,PriceQuoted 
      ,RequiredBy 
      ,Isnull(c.Net,0.00) Net 
      ,[Qty.] QtyApplicable 
       ,Status=case 
        when ItemCode is null then 'Not in Catalog' 
        when [From] > getdate() then 'Availle only on or after '+Convert(varchar(30),[From],106) 
        when datediff(DD,getdate(),isnull(nullif([To],''),'4712-01-01')) < 1 then 'EXPIRED' 
        when items.PriceQuoted != c.Net then 'Quoted Price does not match Catalog price' 
        else coalesce(c.[Item Code],'Invalid/non-existent Item') 
       end 

from @items items 
Left Join ediCatalog c on ltrim(c.[Item Code])=[ItemCode] AND [email protected] AND c.[Customer Id.] [email protected] and c.[Server]=dbo.fsBaanServer() 

) 

ALTER proc [dbo].[prCatalogItems](@comno varchar(3),@cuno varchar(6), 
            @items ttOrderItems readonly) as 
Begin 
    select * from dbo.ftCatalogItems(@comno,@cuno,@items) 
end; 
+0

你可以發佈調用存儲過程並傳遞參數的'C#'代碼嗎? – smr5 2014-10-31 20:47:43

+0

例外中有更多信息。此外,您還沒有提供實際錯誤所在的T-SQL。這段代碼與錯誤無關。關閉。 – usr 2014-10-31 20:59:07

回答

2

你不需要AddWithValue,你也不需要指定UDTT名稱要調用存儲過程(指定TypeName僅需要參數特設SQL)。

prms集合中對象的類型是什麼?你有什麼要傳遞的SqlParameter.Valuehttp://msdn.microsoft.com/en-us/library/bb675163.aspx)三個選項:

  1. 的DataTable
  2. DbDataReader
  3. 返回IEnumerable的方法

所以,要做的主要事情是:

  1. 請確保您通過以上任一項
  2. 保留行p.SqlDbType = SqlDbType.Structured;
  3. 不要使用`.ToString()';
  4. 擺脫整個cmd.Parameters.AddWithValue(p.ParameterName, p.Value.ToString());行,因爲值是通過if (prms.Keys.Contains(pname)) p.Value = prms[pname];設置的。
  5. 移動p.SqlDbType = SqlDbType.Structured;達到switch (sx[0].ToLower())並通過else擺脫if (sx[0] == "table type")塊,但明顯保持cmd.Parameters.Add(p);
+0

你釘了它,我通過第三個參數..(udtt)作爲一個字符串? ,我是多麼愚蠢。謝謝 – TonyP 2014-11-01 13:43:10

+0

@TonyP,不是愚蠢的,有時當你長時間看着它時,很難看到大海撈針。另外,如果不清楚,你不需要整行'cmd.Parameters.AddWithValue(p.ParameterName,p.Value.ToString());',因爲這個值已經設置在頂端了。 – 2014-11-01 13:50:28

+0

,所需的唯一更改是,cmd.Parameters.AddWithValue(p.ParameterName,p.Value);而不是cmd.Parameters.AddWithValue(p.ParameterName,p.Value.ToString());再次感謝。 – TonyP 2014-11-01 14:02:43

相關問題