【发布时间】:2021-11-10 20:45:56
【问题描述】:
我正在尝试将我的DataTable 传递给存储过程。 DataTable 保存 Excel 工作表的内容。 Excel 工作表有两个空列,五个包含文本,五个包含十进制数字。
空列是OppdragsMVAkode 和OppdragsgebyrMVAkode。
如果我运行我的应用程序,我会收到以下异常:
System.ArgumentException:输入字符串的格式不正确。无法将 存储在 OppdragsMVAkode 列中。预期类型是 Decimal。
如果我添加一个临时号码,我会收到以下异常:
System.Data.SqlClient.SqlException:将数据类型 nvarchar 转换为数字时出错。
我不明白为什么它将它作为字符串读取。
我的存储过程(spGetTrips):
ALTER PROCEDURE [dbo].[spGetTrips]
@trips udtTripsPerMonth readonly
AS
BEGIN
INSERT INTO tblTripsPerMonth
SELECT
[KjøretøyID],
SUBSTRING([År], 7, 4),
SUBSTRING([Måned], 4, 2),
[Betaling (brutto)],
[Betaling (netto)],
[Bestillingsgebyr (netto)],
[Betalingsgebyr (netto)],
[OppdragsMVAkode],
CONCAT(LøyvehaverFakturaID, + 'UF-' + SUBSTRING([År], 9, 2) + SUBSTRING([Måned], 4, 2)),
[Oppdragsgebyr (netto)],
[OppdragsgebyrMVAkode],
CONCAT([RidelRegionFakturaID], + 'UF-' + SUBSTRING([År], 9, 2) + SUBSTRING([Måned], 4, 2))
FROM @trips
UPDATE tblTripsPerMonth
SET [OppdragsMVAkode] = (
SELECT [ID]
FROM [tblMVAkoder]
WHERE [ID] = 'MVAkode2'
);
UPDATE tblTripsPerMonth
SET [OppdragsgebyrMVAkode] = (
SELECT [ID]
FROM [tblMVAkoder]
WHERE [ID] = 'MVAkode5'
);
END
正如您在上面看到的,我在存储过程中使用UPDATE 子句设置两个空列的值。无论它们在 Excel 工作表中是空的,还是具有一些初步值,然后被覆盖,我不在乎 - 我只想让它工作。
这是我的用户定义表类型 (udtTripsPerMonth):
CREATE TYPE [dbo].[udtTripsPerMonth] AS TABLE(
[KjøretøyID] [nvarchar](50) NULL,
[År] [nvarchar](50) NULL,
[Måned] [nvarchar](50) NULL,
[Betaling (brutto)] [decimal](10, 2) NULL,
[Betaling (netto)] [decimal](10, 2) NULL,
[Bestillingsgebyr (netto)] [decimal](10, 2) NULL,
[Betalingsgebyr (netto)] [decimal](10, 2) NULL,
[OppdragsMVAkode] [decimal](10, 2) NULL,
[LøyvehaverFakturaID] [nvarchar](50) NULL,
[Oppdragsgebyr (netto)] [decimal](10, 2) NULL,
[OppdragsgebyrMVAkode] [decimal](10, 2) NULL,
[RidelRegionFakturaID] [nvarchar](50) NULL
)
GO
还有我的桌子 (tblTripsPerMonth):
CREATE TABLE [dbo].[tblTripsPerMonth](
[ID] [int] IDENTITY(1,1) NOT NULL,
[KjøretøyID] [nvarchar](50) NULL,
[År] [nvarchar](50) NULL,
[Måned] [nvarchar](50) NULL,
[Betaling (brutto)] [decimal](10, 2) NULL,
[Betaling (netto)] [decimal](10, 2) NULL,
[Bestillingsgebyr (netto)] [decimal](10, 2) NULL,
[Betalingsgebyr (netto)] [decimal](10, 2) NULL,
[OppdragsMVAkode] [decimal](10, 2) NULL,
[LøyvehaverFakturaID] [nvarchar](50) NULL,
[Oppdragsgebyr (netto)] [decimal](10, 2) NULL,
[OppdragsgebyrMVAkode] [decimal](10, 2) NULL,
[RidelRegionFakturaID] [nvarchar](50) NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
我在UPDATE 子句中引用的另一个表(tblMVAkoder):
CREATE TABLE [dbo].[tblMVAkoder](
[ID] [nvarchar](50) NOT NULL,
[Startdato] [date] NULL,
[Sluttdato] [date] NULL,
[MVAsats] [decimal](10, 2) NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
这是我的 C# 代码(Excel 到 DataTable):
private void btnExport_Click(object sender, RoutedEventArgs e) {
OpenFileDialog of = new();
of.Filter = "Excel Files | *.xlsx;";
of.Title = "Importer Excel fil.";
if (of.ShowDialog() == true) {
dgPaidTrip.ItemsSource = ImportExceltoDataTable(of.FileName).DefaultView;
btnClearForm.IsEnabled = true;
}
using (SqlConnection con = new(ConnectionString.connectionString))
using (var cmd = new SqlCommand("spGetTrips", con) { CommandType = CommandType.StoredProcedure }) {
con.Open();
DataTable dt = ImportExceltoDataTable(of.FileName);
cmd.Parameters.Add(new SqlParameter("@trips", dt));
cmd.ExecuteNonQuery();
}
}
public static DataTable ImportExceltoDataTable(string filePath) {
using (XLWorkbook wb = new(filePath)) {
IXLWorksheet ws = wb.Worksheet(1);
int tl_Row = ws.FirstCellUsed().Address.RowNumber;
int tl_Col = ws.FirstCellUsed().Address.ColumnNumber;
int br_Row = ws.LastCellUsed().Address.RowNumber;
int br_Col = ws.LastCellUsed().Address.ColumnNumber;
DataTable dt = new();
dt.Columns.Add("KjøretøyID", typeof(string));
dt.Columns.Add("År", typeof(string));
dt.Columns.Add("Måned", typeof(string));
dt.Columns.Add("Betaling (brutto)", typeof(decimal));
dt.Columns.Add("Betaling (netto)", typeof(decimal));
dt.Columns.Add("Bestillingsgebyr (netto)", typeof(decimal));
dt.Columns.Add("Betalingsgebyr (netto)", typeof(decimal));
dt.Columns.Add("OppdragsMVAkode", typeof(decimal));
dt.Columns.Add("LøyvehaverFakturaID", typeof(string));
dt.Columns.Add("Oppdragsgebyr (netto)", typeof(decimal));
dt.Columns.Add("OppdragsgebyrMVAkode", typeof(decimal));
dt.Columns.Add("RidelRegionFakturaID", typeof(string));
IXLRow currentRow;
for (int dtRow = 0; dtRow < br_Row - tl_Row; dtRow++) {
currentRow = ws.Row(tl_Row + dtRow + 1);
dt.Rows.Add();
for (int dtCol = 0; dtCol < br_Col - tl_Col + 1; dtCol++) {
dt.Rows[dtRow][dtCol] = currentRow.Cell(tl_Col + dtCol).Value;
}
}
return dt;
}
}
据我所知,我的所有列类型以及它们的顺序都匹配。
我将所有类型更改为nvarchar,并且代码“有效”。
但是比我聪明的人告诉我,伪造列类型不是一个好主意。
我错过了什么?
【问题讨论】:
-
您是否尝试过将您要发送的
DataTable的SqlDBType设置为Structured?第一个错误与ImportExceltoDataTable=>dt.Rows[dtRow][dtCol] = currentRow.Cell(tl_Col + dtCol).Value;FWIW 有关 -
对于第二个问题,我会在您的程序中加入某种 try/catch/begin catch 语句,以帮助准确追踪问题发生的位置。您可以获取过程名称、行号、确切消息等,并将该错误记录在另一个表中或返回并检查。
-
正如所指出的,问题在于
dt.Rows[dtRow][dtCol] = currentRow.Cell(tl_Col + dtCol).Value,这是因为它将所有单元格值添加为字符串数据。如果Betaling (brutto)、Betaling (netto)、Bestillingsgebyr (netto)、Betalingsgebyr (netto)、OppdragsMVAkode、Oppdragsgebyr (netto)和Oppdragsgebyr (netto)和OppdragsgebyrMVAkode的 Cell.Values 为空白,或者看起来不像十进制数字,您应该发送 @ 987654351@ 而不是逐字传递字符串。 -
@zaggler 感谢您的评论。我确实尝试将
SqlDBType设置为Structured,但异常仍然存在。我一直在尝试更改您和@AlwaysLearning(也感谢您的评论)正在引用的行,但我没有成功。我将如何发送 DBNull.Value?我尝试在我的dt.Columns.Add部分中将AllowDBNull = true添加到有问题的列中,但这不起作用。
标签: c# sql-server excel stored-procedures datatable