简体   繁体   English

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

[英]c# System.InvalidCastException when passing datatable to stored procedure

I'm defining a UDT in my MS SQL Server 2012 DB and using that in a stored procedure in the database. 我在MS SQL Server 2012 DB中定义了UDT,并在数据库的存储过程中使用了UDT。 I'm trying to call my stored procedure from my c# program and I'm getting an error. 我正在尝试从c#程序调用存储过程,但出现错误。 Here's my code: 这是我的代码:

This is the definition of my UDT: 这是我的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
)

Here is my stored procedure definition: 这是我的存储过程定义:

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

Here is my c# class file where I define my datatable and populate it with data: 这是我的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;
        }
    }
}

and lastly here is my code where I initialize my datatable and try to pass it to the stored procedure in my database: 最后,这是我的代码,在该代码中我初始化数据表,然后尝试将其传递给数据库中的存储过程:

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

Running my code gives me this error: 运行我的代码给我这个错误:

System.InvalidCastException: 'Failed to convert parameter value from a PP_ISP_File_Data to a IEnumerable`1.' System.InvalidCastException:'无法将参数值从PP_ISP_File_Data转换为IEnumerable`1。

I have a suspicion that because I'm declaring my datatable in a class file it's not getting something that it needs to be able to enumerate over it when it gets passed to the stored procedure but I don't know how to correct that. 我有一个怀疑,因为我在类文件中声明了数据表,所以在将其传递给存储过程时没有得到它需要能够枚举的东西,但是我不知道该如何纠正。 Can someone please point me in the right direction to fix this? 有人可以指出正确的方向来解决此问题吗? Thanks in advance. 提前致谢。

You actually need to pass datatable as parameter to the stored procedure for it to be used as UDT but right now you are passing whole object of your class which will not work. 实际上,您需要将数据表作为参数传递给存储过程,以使其用作UDT,但现在您正在传递类的整个对象,该对象将无法工作。

So change the following line: 因此,更改以下行:

spFilenames.Value = dtFileInfo;

to: 至:

spFilenames.Value = dtFileInfo.dt_Files_Info;

From MSDN : 从MSDN

System.Data.SqlClient supports populating table-valued parameters from DataTable , DbDataReader or IEnumerable \\ SqlDataRecord objects. System.Data.SqlClient支持从DataTableDbDataReaderIEnumerable \\ SqlDataRecord对象填充表值参数。

Also refer to Passing a Table-Valued Parameter to a Stored Procedure 另请参阅将表值参数传递给存储过程

You can take a look at the following posts for more: 您可以查看以下帖子以了解更多信息:

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

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

Hope it helps. 希望能帮助到你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM