我正在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。
我怀疑是因为我在类文件中声明了数据表,所以在传递给存储过程时没有得到它需要能够枚举的东西,但是我不知道如何更正那。有人可以指出正确的方向来解决此问题吗?预先感谢。
答案 0 :(得分:1)
实际上,您需要将数据表作为参数传递给存储过程,以使其用作UDT,但现在您正在传递类的整个对象,这将不起作用。
因此更改以下行:
spFilenames.Value = dtFileInfo;
收件人:
spFilenames.Value = dtFileInfo.dt_Files_Info;
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
希望有帮助。