2014-10-31 16 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

相关问题