2014-10-31 4 views
1

3 개의 매개 변수를 사용하는 저장 프로 시저가 있습니다. 첫 번째 및 두 번째 매개 변수는 varchar 유형이고 마지막 매개 변수는 사용자 정의 테이블 유형입니다.UDTT (User-Defined Table Type) 매개 변수를 다른 유형과 혼합 할 수 있습니까?

[System.Data.SqlClient.SqlException] = { "피연산자 타입 충돌 : NVARCHAR가 ttOrderItems와 호환되지 않는"}

I가 ExecuteNonQuery 통해 저장 프로 시저를 EXEC

는 그 예외가 발생

ttOrderItems은 사용자 정의 테이블 유형입니다.

이 동작이 정상입니까? 매개 변수 중 하나가 사용자 정의 테이블 유형 인 경우 매개 변수를 혼합하지 않습니다. 나는 T-SQL을 다음을 통해 동일한 시저를 간부 인 때, 예상대로 작동

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

:

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

+0

예외에 더 많은 정보가 있습니다. 또한 실제 오류가 발생한 곳의 T-SQL을 제공하지 않았습니다.이 대량의 코드는 오류와 아무 관련이 없습니다. 폐쇄. – usr

답변

2

당신은 AddWithValue이 필요 없으며이 (TypeName 만 매개 변수화 된 임시 SQL에 필요한 지정) 저장 프로 시저를 호출하는대로 UDTT 이름을 지정할 필요하지 않습니다.

prms 컬렉션의 개체 유형은 무엇입니까? 당신은 SqlParameter.Value (http://msdn.microsoft.com/en-us/library/bb675163.aspx)로 통과하는 것의 세 가지 옵션이 있습니다 IEnumerable을 반환

  1. DataTable을
  2. DbDataReader에서
  3. 방법을

그래서, 할 수있는 중요한 것은입니다 :

  1. 위 항목 중 하나를 통과해야합니다.
  2. 행을 유지하십시오 p.SqlDbType = SqlDbType.Structured;
  3. `.ToString() ';을 사용하지 마십시오.
  4. 을 통해 값이 설정되면 전체 cmd.Parameters.AddWithValue(p.ParameterName, p.Value.ToString()); 줄을 제거하십시오.
  5. p.SqlDbType = SqlDbType.Structured;switch (sx[0].ToLower())까지 이동하고 else을 통해 if (sx[0] == "table type") 블록을 제거하지만 분명히 cmd.Parameters.Add(p);을 유지하십시오.
+0

당신은 그것을 박 혔어, 나는 세 번째 매개 변수를 전달했다 .. (udtt) 문자열로? , 얼마나 바보 야? 고마워요 – TonyP

+0

@ TonyP, 바보가 아니고, 때로는 오랫동안 그것을 보았을 때 건초 더미에서 바늘을 볼 수 있습니다. 또한 명확하지 않은 경우 값이 이미 위쪽으로 설정되어 있으므로'cmd.Parameters.AddWithValue (p.ParameterName, p.Value.ToString()); '행 전체가 필요하지 않습니다. –

+0

, 필요한 유일한 변경 사항은 cmd.Parameters.AddWithValue (p.ParameterName, p.Value); 대신 cmd.Parameters.AddWithValue (p.ParameterName, p.Value.ToString()); 다시 한번 감사드립니다. – TonyP