如何在 .NET Core 上的 C# 中调用具有多种类型的存储过程

How to call a stored procedure that has several types in C# on .NET Core

我写了一个存储过程,它将我创建的两种类型作为参数,分别称为 Type1Type2 :

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;.