将数据表传递到存储过程时,c#System.InvalidCastException

时间:2018-11-21 04:24:42

标签: c# sql-server datatable parameter-passing

我正在MS SQL Server 2012 DB中定义UDT,并在数据库的存储过程中使用它。我正在尝试从c#程序调用存储过程,但出现错误。这是我的代码:

这是我的UDT的定义:

CREATE TYPE [dbo].[udt_850File] AS TABLE(
    [strInbound850FromPharmacyFilename] [nvarchar](1000) NULL,
    [strSenderID_ISA06] [nvarchar](15) NOT NULL,
    [strReceiverID_ISA08] [nvarchar](15) NOT NULL,
    [strInterchangeControlVersion_ISA12] [nvarchar](5) NOT NULL,
    [strInterchangeControlNumber_ISA13] [nvarchar](9) NOT NULL,
    [chElementDelimiter] [nchar](1) NOT NULL,
    [chComponentElementDelimiter] [nchar](1) NOT NULL,
    [chSegmentTerminator] [nchar](1) NOT NULL,
    [intTransmissionDate_GS04] [int] NOT NULL,
    [strVersionRelease_GS08] [nvarchar](12) NOT NULL,
    [strTransSetControl_ST02] [nvarchar](9) NOT NULL,
    [strPONumber_BEG03] [nvarchar](22) NOT NULL,
    [intPODate_BEG05] [int] NOT NULL,
    [strWholesalerAccountNum_N1BY04] [nvarchar](80) NOT NULL,
    [dtFileCreatedDateTime] [datetime] NOT NULL
)

这是我的存储过程定义:

CREATE PROCEDURE [dbo].[ppisp_sp_850Files_Insert]
    @850FileData [dbo].[udt_850File] READONLY
AS
    BEGIN

        DECLARE @ReturnVal INT = 0

        MERGE INTO [dbo].[850Files] AS target
        USING @850FileData AS source
            ON source.[strInbound850FromPharmacyFilename] = target.[strInbound850FromPharmacyFilename]
            AND source.[strSenderID_ISA06] = target.[strSenderID_ISA06]
            AND source.[strReceiverID_ISA08] = target.[strReceiverID_ISA08]
            AND source.[strInterchangeControlVersion_ISA12] = target.[strInterchangeControlVersion_ISA12]
            AND source.[strInterchangeControlNumber_ISA13] = target.[strInterchangeControlNumber_ISA13]
            AND source.[chElementDelimiter] = target.[chElementDelimiter]
            AND source.[chComponentElementDelimiter] = target.[chComponentElementDelimiter]
            AND source.[chSegmentTerminator] = target.[chSegmentTerminator]
            AND source.[intTransmissionDate_GS04] = target.[intTransmissionDate_GS04]
            AND source.[strVersionRelease_GS08] = target.[strVersionRelease_GS08]
            AND source.[strTransSetControl_ST02] = target.[strTransSetControl_ST02]
            AND source.[strPONumber_BEG03] = target.[strPONumber_BEG03]
            AND source.[intPODate_BEG05] = target.[intPODate_BEG05]
            AND source.[strWholesalerAccountNum_N1BY04] = target.[strWholesalerAccountNum_N1BY04]
            AND source.[dtFileCreatedDateTime] = target.[dtFileCreatedDateTime]
        WHEN NOT MATCHED BY TARGET THEN
            INSERT ([strInbound850FromPharmacyFilename]
                    , [strSenderID_ISA06]
                    , [strReceiverID_ISA08]
                    , [strInterchangeControlVersion_ISA12]
                    , [strInterchangeControlNumber_ISA13]
                    , [chElementDelimiter]
                    , [chComponentElementDelimiter]
                    , [chSegmentTerminator]
                    , [intTransmissionDate_GS04]
                    , [strVersionRelease_GS08]
                    , [strTransSetControl_ST02]
                    , [strPONumber_BEG03]
                    , [intPODate_BEG05]
                    , [strWholesalerAccountNum_N1BY04]
                    , [dtFileCreatedDateTime])
            VALUES (source.[strInbound850FromPharmacyFilename]
                    , source.[strSenderID_ISA06]
                    , source.[strReceiverID_ISA08]
                    , source.[strInterchangeControlVersion_ISA12]
                    , source.[strInterchangeControlNumber_ISA13]
                    , source.[chElementDelimiter]
                    , source.[chComponentElementDelimiter]
                    , source.[chSegmentTerminator]
                    , source.[intTransmissionDate_GS04]
                    , source.[strVersionRelease_GS08]
                    , source.[strTransSetControl_ST02]
                    , source.[strPONumber_BEG03]
                    , source.[intPODate_BEG05]
                    , source.[strWholesalerAccountNum_N1BY04]
                    , source.[dtFileCreatedDateTime]);

            SET @ReturnVal = @@ROWCOUNT
    END

这是我的c#类文件,在其中定义我的数据表并用数据填充它:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;

namespace PP_ISP_File
{
    public class PP_ISP_File_Data 
    {
        public DataTable dt_Files_Info { get; set; }

        public PP_ISP_File_Data(string strFileDirectoryPath, int intFileType)
        {
            dt_Files_Info = new DataTable();
            dt_Files_Info.Columns.Add("strSenderID_ISA06", typeof(string));
            dt_Files_Info.Columns["strSenderID_ISA06"].DefaultValue = default(string);
            dt_Files_Info.Columns.Add("strReceiverID_ISA08", typeof(string));
            dt_Files_Info.Columns["strReceiverID_ISA08"].DefaultValue = default(string);
            dt_Files_Info.Columns.Add("strInterchangeControlVersion_ISA12", typeof(string));
            dt_Files_Info.Columns["strInterchangeControlVersion_ISA12"].DefaultValue = default(string);
            dt_Files_Info.Columns.Add("strInterchangeControlNumber_ISA13", typeof(string));
            dt_Files_Info.Columns["strInterchangeControlNumber_ISA13"].DefaultValue = default(string);
            dt_Files_Info.Columns.Add("chElementDelimiter", typeof(char));
            dt_Files_Info.Columns["chElementDelimiter"].DefaultValue = default(char);
            dt_Files_Info.Columns.Add("chComponentElementDelimiter", typeof(char));
            dt_Files_Info.Columns["chComponentElementDelimiter"].DefaultValue = default(char);
            dt_Files_Info.Columns.Add("chSegmentTerminator", typeof(char));
            dt_Files_Info.Columns["chSegmentTerminator"].DefaultValue = default(char);
            dt_Files_Info.Columns.Add("intTransmissionDate_GS04", typeof(int));
            dt_Files_Info.Columns["intTransmissionDate_GS04"].DefaultValue = -1;
            dt_Files_Info.Columns.Add("strVersionRelease_GS08", typeof(string));
            dt_Files_Info.Columns["strVersionRelease_GS08"].DefaultValue = default(string);
            dt_Files_Info.Columns.Add("strTransSetControl_ST02", typeof(string));
            dt_Files_Info.Columns["strTransSetControl_ST02"].DefaultValue = default(string);

            if(intFileType == 850)
            {
                dt_Files_Info.Columns.Add("strInbound850FromPharmacyFilename", typeof(string));
                dt_Files_Info.Columns["strInbound850FromPharmacyFilename"].DefaultValue = default(string);
                dt_Files_Info.Columns.Add("strPONumber_BEG03", typeof(string));
                dt_Files_Info.Columns["strPONumber_BEG03"].DefaultValue = default(string);
                dt_Files_Info.Columns.Add("intPODate_BEG05", typeof(int));
                dt_Files_Info.Columns["intPODate_BEG05"].DefaultValue = -1;
                dt_Files_Info.Columns.Add("strWholesalerAccountNum_N1BY04", typeof(string));
                dt_Files_Info.Columns["strWholesalerAccountNum_N1BY04"].DefaultValue = default(string);
            }
            else if(intFileType == 855)
            {
                dt_Files_Info.Columns.Add("strOutbound855ToPharmacyFilename", typeof(string));
                dt_Files_Info.Columns["strOutbound855ToPharmacyFilename"].DefaultValue = default(string);
                dt_Files_Info.Columns.Add("strPONumber_BAK03", typeof(string));
                dt_Files_Info.Columns["strPONumber_BAK03"].DefaultValue = default(string);
                dt_Files_Info.Columns.Add("intPODate_BAK04", typeof(int));
                dt_Files_Info.Columns["intPODate_BAK04"].DefaultValue = -1;
                dt_Files_Info.Columns.Add("strWholesalerAccountNum_N1ST04", typeof(string));
                dt_Files_Info.Columns["strWholesalerAccountNum_N1ST04"].DefaultValue = default(string);
            }

            dt_Files_Info.Columns.Add("dtFileCreatedDateTime", typeof(DateTime));
            dt_Files_Info.Columns["dtFileCreatedDateTime"].DefaultValue = default(DateTime);

            dt_Files_Info = GetFileDetails(strFileDirectoryPath, intFileType);
        }

       private DataTable GetFileDetails(string strFileDirectoryPath, int intFileType)
        {
            DataTable dtPP_ISP_Files_Return = dt_Files_Info.Clone();

            DirectoryInfo diDirectoryInfo = new DirectoryInfo(strFileDirectoryPath);

            if (diDirectoryInfo.Exists)
            {
                foreach (FileInfo fiFileInfo in diDirectoryInfo.GetFiles())
                {
                    if (fiFileInfo.Exists)
                    {
                        using (StreamReader srFile = new StreamReader(fiFileInfo.FullName))
                        {
                            string strFileData = System.IO.File.ReadAllText(fiFileInfo.FullName);
                            if (strFileData.Length >= 104)
                            {
                                DataRow dr = dtPP_ISP_Files_Return.NewRow();

                                char chElementDelimiter = default(char);
                                char chComponentElementDelimiter = default(char);
                                char chSegmentTerminator = default(char);

                                chElementDelimiter = Convert.ToChar(strFileData.Substring(3, 1));
                                dr["chElementDelimiter"] = chElementDelimiter;
                                chComponentElementDelimiter = Convert.ToChar(strFileData.Substring(104, 1));
                                dr["chComponentElementDelimiter"] = chComponentElementDelimiter;
                                chSegmentTerminator = Convert.ToChar(strFileData.Substring(105, 1));
                                dr["chSegmentTerminator"] = chSegmentTerminator;
                                dr["dtFileCreatedDateTime"] = File.GetCreationTime(strFileDirectoryPath);

                                string[] arrFileLines = strFileData.Split(Convert.ToChar(chSegmentTerminator));

                                for (int i = 0; i <= arrFileLines.Length - 1; i++)
                                {
                                    string[] arrLineData = arrFileLines[i].Split(Convert.ToChar(chElementDelimiter));
                                    string strLineQualifier = arrLineData[0].Trim();

                                    switch (strLineQualifier)
                                    {
                                        case "ISA":
                                            dr["strSenderID_ISA06"] = arrLineData[6].Trim();
                                            dr["strReceiverID_ISA08"] = arrLineData[8].Trim();
                                            dr["strInterchangeControlVersion_ISA12"] = arrLineData[12].Trim();
                                            dr["strInterchangeControlNumber_ISA13"] = arrLineData[13].Trim();
                                            break;
                                        case "GS":
                                            dr["intTransmissionDate_GS04"] = Convert.ToInt32(arrLineData[4].Trim());
                                            dr["strVersionRelease_GS08"] = arrLineData[8].Trim();
                                            break;
                                        case "ST":
                                            dr["strTransSetControl_ST02"] = arrLineData[2].Trim();
                                            break;
                                        case "BEG":
                                            dr["strInbound850FromPharmacyFilename"] = fiFileInfo.Name;                                            
                                            dr["strPONumber_BEG03"] = arrLineData[3].Trim();
                                            dr["intPODate_BEG05"] = Convert.ToInt32(arrLineData[5].Trim());
                                            break;
                                        case "BAK":
                                            dr["strOutbound855ToPharmacyFilename"] = fiFileInfo.Name;
                                            dr["strPONumber_BAK03"] = arrLineData[3].Trim();
                                            dr["intPODate_BAK04"] = Convert.ToInt32(arrLineData[4].Trim());
                                            break;
                                        case "N1":
                                            if(arrLineData[1].Trim() == "BY")
                                            {
                                                dr["strWholesalerAccountNum_N1BY04"] = arrLineData[4].Trim();
                                                dtPP_ISP_Files_Return.Rows.Add(dr);
                                            }
                                            else if (arrLineData[1].Trim() == "ST")
                                            {
                                                dr["strWholesalerAccountNum_N1ST04"] = arrLineData[4].Trim();
                                                dtPP_ISP_Files_Return.Rows.Add(dr);
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return dtPP_ISP_Files_Return;
        }
    }
}

最后,这是我的代码,在该代码中我初始化数据表,然后尝试将其传递给数据库中的存储过程:

using (SqlCommand cmd = new SqlCommand(strSPName, con))
{
    PP_ISP_File_Data dtFileInfo = new PP_ISP_File_Data(strWatchPath, intFileType);

    cmd.CommandText = strSPName;
    cmd.CommandType = System.Data.CommandType.StoredProcedure;

    SqlParameter spFilenames = new SqlParameter("@850FileData", SqlDbType.Structured);
    spFilenames.TypeName = "dbo.udt_850File";
    spFilenames.Value = dtFileInfo;

    cmd.Parameters.Add(spFilenames);

    SqlParameter returnParameter = new SqlParameter("@ReturnVal", SqlDbType.Int);
    returnParameter.Direction = ParameterDirection.ReturnValue;

    cmd.Parameters.Add(returnParameter);

    con.Open();
    cmd.ExecuteNonQuery();
    int result = Convert.ToInt16(returnParameter.Value);
}

运行我的代码会给我这个错误:

  

System.InvalidCastException:'无法从参数转换参数值   将PP_ISP_File_Data转换为IEnumerable`1。

我怀疑是因为我在类文件中声明了数据表,所以在传递给存储过程时没有得到它需要能够枚举的东西,但是我不知道如何更正那。有人可以指出正确的方向来解决此问题吗?预先感谢。

1 个答案:

答案 0 :(得分:1)

实际上,您需要将数据表作为参数传递给存储过程,以使其用作UDT,但现在您正在传递类的整个对象,这将不起作用。

因此更改以下行:

spFilenames.Value = dtFileInfo;

收件人:

spFilenames.Value = dtFileInfo.dt_Files_Info;

From MSDN

  

System.Data.SqlClient 支持从 DataTable DbDataReader IEnumerable \ SqlDataRecord 填充表值参数对象。

另请参阅Passing a Table-Valued Parameter to a Stored Procedure

您可以查看以下帖子以获取更多信息:

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters

https://visualstudiomagazine.com/articles/2015/06/01/table-valued-parameters.aspx

希望有帮助。