如何在 .NET Core 上的 C# 中调用具有多种类型的存储过程
How to call a stored procedure that has several types in C# on .NET Core
我写了一个存储过程,它将我创建的两种类型作为参数,分别称为 Type1
和 Type2
:
CREATE TYPE Type1 AS TABLE
(
Id [int] NULL,
Value [float] NULL
)
CREATE TYPE Type2 AS TABLE
(
Id [int] NULL,
Name [varchar](20) NULL,
Value [float] NULL
)
CREATE PROCEDURE [SP-Name]
(@Id INT = 1,
@UserName VARCHAR(500) = 'test',
@Item1 Type1 READONLY,
@Item2 Type2 READONLY)
AS
BEGIN
SELECT *
FROM @Item1
END;
当我在 SQL 服务器本身调用这个存储过程时,它运行没有错误,但是我在 C# 中编写相同的代码时,我得到了一个错误。有什么问题?
这就是我在 C# 中调用此存储过程的方式:
ENTITIES.SqlQuery<Result>($"EXEC [SP-Name] @Item1",
new[] {
new SqlParameter
{
SqlDbType = SqlDbType.Structured,
TypeName = "Type1",
Value = listItems.ToDataTable(),//Get list Item from database and Convert to DATA-TABLE
ParameterName = "Item1"
}}).ToList();
public class Result
{
public int Id { get; set; }
public string Value { get; set; }
}
public static DataTable ToDataTable<T>(this List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
// Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
// Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
// Setting column names as Property names
dataTable.Columns.Add(prop.Name, type);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
// inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
// put a breakpoint here and check datatable
return dataTable;
}
这是我得到的错误:
Operand type clash: Item1 is incompatible with int
这里的问题是您认为因为您有一个名为 @Item1
的变量,所以 SQL 服务器会推断它是参数 @Item1
,因为它们同名;这个假设是错误的。
当您省略传递变量的参数时,变量(或文字)将根据序号位置传递给参数。您为参数 @Item1
传递 一个 值,该值将传递给您的 第一个 参数 @Id
。这就是您收到错误的原因。 @Item1
被定义为结构化数据类型(SqlDbType.Structured
),但是@Id
是一个int
;没有相同的数据类型,你会得到一个错误。
如果您想省略参数,请明确说明您传递的参数:
ENTITIES.SqlQuery<Result>($"EXEC dbo.[SP-Name] @Item1 = @Item1;",
或者,可能更好,只是从过程中删除所有其他参数,因为您不使用它们:
CREATE PROCEDURE dbo.[SP-Name] @Item1 Type1 READONLY
AS
BEGIN
SELECT *
FROM @Item1;
END;
那你就可以使用EXEC dbo.[SP-Name] @Item1;
.
我写了一个存储过程,它将我创建的两种类型作为参数,分别称为 Type1
和 Type2
:
CREATE TYPE Type1 AS TABLE
(
Id [int] NULL,
Value [float] NULL
)
CREATE TYPE Type2 AS TABLE
(
Id [int] NULL,
Name [varchar](20) NULL,
Value [float] NULL
)
CREATE PROCEDURE [SP-Name]
(@Id INT = 1,
@UserName VARCHAR(500) = 'test',
@Item1 Type1 READONLY,
@Item2 Type2 READONLY)
AS
BEGIN
SELECT *
FROM @Item1
END;
当我在 SQL 服务器本身调用这个存储过程时,它运行没有错误,但是我在 C# 中编写相同的代码时,我得到了一个错误。有什么问题?
这就是我在 C# 中调用此存储过程的方式:
ENTITIES.SqlQuery<Result>($"EXEC [SP-Name] @Item1",
new[] {
new SqlParameter
{
SqlDbType = SqlDbType.Structured,
TypeName = "Type1",
Value = listItems.ToDataTable(),//Get list Item from database and Convert to DATA-TABLE
ParameterName = "Item1"
}}).ToList();
public class Result
{
public int Id { get; set; }
public string Value { get; set; }
}
public static DataTable ToDataTable<T>(this List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
// Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
// Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
// Setting column names as Property names
dataTable.Columns.Add(prop.Name, type);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
// inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
// put a breakpoint here and check datatable
return dataTable;
}
这是我得到的错误:
Operand type clash: Item1 is incompatible with int
这里的问题是您认为因为您有一个名为 @Item1
的变量,所以 SQL 服务器会推断它是参数 @Item1
,因为它们同名;这个假设是错误的。
当您省略传递变量的参数时,变量(或文字)将根据序号位置传递给参数。您为参数 @Item1
传递 一个 值,该值将传递给您的 第一个 参数 @Id
。这就是您收到错误的原因。 @Item1
被定义为结构化数据类型(SqlDbType.Structured
),但是@Id
是一个int
;没有相同的数据类型,你会得到一个错误。
如果您想省略参数,请明确说明您传递的参数:
ENTITIES.SqlQuery<Result>($"EXEC dbo.[SP-Name] @Item1 = @Item1;",
或者,可能更好,只是从过程中删除所有其他参数,因为您不使用它们:
CREATE PROCEDURE dbo.[SP-Name] @Item1 Type1 READONLY
AS
BEGIN
SELECT *
FROM @Item1;
END;
那你就可以使用EXEC dbo.[SP-Name] @Item1;
.