C# 无法使用EF Core使用命名参数和输出参数执行SQL Server SP

C# 无法使用EF Core使用命名参数和输出参数执行SQL Server SP,c#,sql-server,linq,.net-core,entity-framework-core,C#,Sql Server,Linq,.net Core,Entity Framework Core,尝试使用实体框架核心从SQL Server执行存储过程时遇到问题。此SP用于通过Econnect将外部数据与客户端ERP(Microsoft Dynamics Great Plains)集成 这是SP元数据(由于正文限制,我仅包括SP DDL行): 这是我试图用来运行SP的代码: private EconnectSpExecutionResult MakeGpTransferBetweenBins(ColonyFuelTransferDto colonyFuelTransferD

尝试使用实体框架核心从SQL Server执行存储过程时遇到问题。此SP用于通过Econnect将外部数据与客户端ERP(Microsoft Dynamics Great Plains)集成

这是SP元数据(由于正文限制,我仅包括SP DDL行):

这是我试图用来运行SP的代码:

        private EconnectSpExecutionResult MakeGpTransferBetweenBins(ColonyFuelTransferDto colonyFuelTransferDb)
    {
        var spExecutionResult = new EconnectSpExecutionResult();
        var spExecQuery = "EXECUTE [dbo].[taIVMultibinBinToBinTransfer] " +
                            "@I_vITEMNMBR" +
                            ", @I_vLOCNCODE" +
                            ", @I_vUOFM" +
                            ", @I_vBIN" +
                            ", @I_vQUANTITY" +
                            ", @I_vTOBIN" +
                            ", @O_iErrorState OUTPUT" +
                            ", @oErrString OUTPUT";

        var fuelItemIdParam = new SqlParameter("@I_vITEMNMBR", colonyFuelTransferDb.FuelItemId);
        var locationGpIdParam = new SqlParameter("@I_vLOCNCODE", colonyFuelTransferDb.LocationGpId);
        var measureUnitIdParam = new SqlParameter("@I_vUOFM", colonyFuelTransferDb.MeasureUnitId);
        var sourceBinIdParam = new SqlParameter("@I_vBIN", colonyFuelTransferDb.SourceBinId);
        var quantityParam = new SqlParameter("@I_vQUANTITY", colonyFuelTransferDb.Quantity);
        var destinationBinIdParam = new SqlParameter("@I_vTOBIN", colonyFuelTransferDb.DestinationBinId);
        var errorNumberParam = new SqlParameter("@O_iErrorState", spExecutionResult.ErrorNumber) { Direction = System.Data.ParameterDirection.Output };
        var errorDescriptionParam = new SqlParameter("@oErrString", spExecutionResult.ErrorDescription) { Direction = System.Data.ParameterDirection.Output, Size = 255 };

        _seaboardGpDbContext
                .Database
                .ExecuteSqlCommand
                (
                    spExecQuery,
                    fuelItemIdParam,
                    locationGpIdParam,
                    measureUnitIdParam,
                    sourceBinIdParam,
                    quantityParam,
                    destinationBinIdParam,
                    errorNumberParam,
                    errorDescriptionParam
                );

        return spExecutionResult;
    }
问题是我不能让它工作。SP有几个我想要避免的参数,让它们采用元数据中指定的默认值。此外,这个SP有两个输出参数,我需要在执行后检索它们,它们为您提供有关集成过程中可能发生的错误的信息

我得到的当前错误如下:将数据类型nvarchar转换为smallint时出错。。从实际运行的查询中可以看出,EF Core似乎没有使用命名参数:

declare @p9 int
set @p9=NULL
declare @p10 nvarchar(255)
set @p10=NULL
exec sp_executesql N'EXECUTE [dbo].[taIVMultibinBinToBinTransfer] @I_vITEMNMBR, @I_vLOCNCODE, @I_vUOFM, @I_vBIN, @I_vQUANTITY, @I_vTOBIN, @O_iErrorState OUTPUT, @oErrString OUTPUT',N'@I_vITEMNMBR nvarchar(9),@I_vLOCNCODE nvarchar(3),@I_vUOFM nvarchar(2),@I_vBIN nvarchar(3),@I_vQUANTITY decimal(6,2),@I_vTOBIN nvarchar(3),@O_iErrorState int output,@oErrString nvarchar(255) output',@I_vITEMNMBR=N'092001122',@I_vLOCNCODE=N'CZE',@I_vUOFM=N'LT',@I_vBIN=N'CZE',@I_vQUANTITY=1007.00,@I_vTOBIN=N'CHZ',@O_iErrorState=@p9 output,@oErrString=@p10 output
select @p9, @p10
如果您能给我任何指导或帮助,我将不胜感激。我尝试过几种选择,但都不奏效。在执行SP之前,我总是会遇到与实体框架核心或sql server引擎相关的异常


谢谢。

问题在于参数将按照接收顺序提供给sp。您希望使用sp中的名称将它们分配给sp,这些名称可以相同

执行的sql基本上如下所示:

declare @I_vITEMNMBR char(30) = .. , 
    @I_vLOCNCODE char(10) = .., 
    @I_vUOFM char(8) = .., 
    @I_vBIN char(15) = .., 
    @I_vQUANTITY numeric(19, 5) = .., 
    @I_vTOBIN char(15) = .., 
    @O_iErrorState int,
    @oErrString varchar(255)

EXECUTE [dbo].[taIVMultibinBinToBinTransfer] 
                        @I_vITEMNMBR
                        , @I_vLOCNCODE
                        , @I_vUOFM
                        , @I_vBIN
                        , @I_vQUANTITY
                        , @I_vTOBIN
                        , @O_iErrorState OUTPUT
                        , @oErrString OUTPUT
@正在将I_vUOFM分配给@I_vQTYTYPE,这是错误的类型

你想要的是:

declare @I_vITEMNMBR char(30) = .., 
    @I_vLOCNCODE char(10) = .., 
    @I_vUOFM char(8) = .., 
    @I_vBIN char(15) = .., 
    @I_vQUANTITY numeric(19, 5) = .., 
    @I_vTOBIN char(15) = .., 
    @O_iErrorState int = ..,
    @oErrString varchar(255) = ..

EXECUTE [dbo].[taIVMultibinBinToBinTransfer] 
                        @I_vITEMNMBR  = @I_vITEMNMBR
                        , @I_vLOCNCODE = @I_vLOCNCODE
                        , @I_vUOFM = @I_vUOFM
                        , @I_vBIN = @I_vBIN
                        , @I_vQUANTITY = @I_vQUANTITY
                        , @I_vTOBIN = @I_vTOBIN
                        , @O_iErrorState = @O_iErrorState OUTPUT
                        , @oErrString = @oErrString OUTPUT
是的,如果您只想提供这些参数,则必须将代码更改为以下内容:

var spExecQuery = @"EXECUTE [dbo].[taIVMultibinBinToBinTransfer] 
                    @I_vITEMNMBR    = @I_vITEMNMBR
                  , @I_vLOCNCODE    = @I_vLOCNCODE
                  , @I_vUOFM        = @I_vUOFM
                  , @I_vBIN         = @I_vBIN
                  , @I_vQUANTITY    = @I_vQUANTITY
                  , @I_vTOBIN       = @I_vTOBIN
                  , @O_iErrorState  = @O_iErrorState OUTPUT
                  , @oErrString     = @oErrString OUTPUT";

问题在于参数将按照接收顺序提供给sp。您希望使用sp中的名称将它们分配给sp,这些名称可以相同

执行的sql基本上如下所示:

declare @I_vITEMNMBR char(30) = .. , 
    @I_vLOCNCODE char(10) = .., 
    @I_vUOFM char(8) = .., 
    @I_vBIN char(15) = .., 
    @I_vQUANTITY numeric(19, 5) = .., 
    @I_vTOBIN char(15) = .., 
    @O_iErrorState int,
    @oErrString varchar(255)

EXECUTE [dbo].[taIVMultibinBinToBinTransfer] 
                        @I_vITEMNMBR
                        , @I_vLOCNCODE
                        , @I_vUOFM
                        , @I_vBIN
                        , @I_vQUANTITY
                        , @I_vTOBIN
                        , @O_iErrorState OUTPUT
                        , @oErrString OUTPUT
@正在将I_vUOFM分配给@I_vQTYTYPE,这是错误的类型

你想要的是:

declare @I_vITEMNMBR char(30) = .., 
    @I_vLOCNCODE char(10) = .., 
    @I_vUOFM char(8) = .., 
    @I_vBIN char(15) = .., 
    @I_vQUANTITY numeric(19, 5) = .., 
    @I_vTOBIN char(15) = .., 
    @O_iErrorState int = ..,
    @oErrString varchar(255) = ..

EXECUTE [dbo].[taIVMultibinBinToBinTransfer] 
                        @I_vITEMNMBR  = @I_vITEMNMBR
                        , @I_vLOCNCODE = @I_vLOCNCODE
                        , @I_vUOFM = @I_vUOFM
                        , @I_vBIN = @I_vBIN
                        , @I_vQUANTITY = @I_vQUANTITY
                        , @I_vTOBIN = @I_vTOBIN
                        , @O_iErrorState = @O_iErrorState OUTPUT
                        , @oErrString = @oErrString OUTPUT
是的,如果您只想提供这些参数,则必须将代码更改为以下内容:

var spExecQuery = @"EXECUTE [dbo].[taIVMultibinBinToBinTransfer] 
                    @I_vITEMNMBR    = @I_vITEMNMBR
                  , @I_vLOCNCODE    = @I_vLOCNCODE
                  , @I_vUOFM        = @I_vUOFM
                  , @I_vBIN         = @I_vBIN
                  , @I_vQUANTITY    = @I_vQUANTITY
                  , @I_vTOBIN       = @I_vTOBIN
                  , @O_iErrorState  = @O_iErrorState OUTPUT
                  , @oErrString     = @oErrString OUTPUT";

可能是一个标志问题。NVARCHAR是两个字节。smallint是带符号位的15位。请尝试删除“执行”文本和sp名称后以文本形式列出的参数。此外,我建议您使用SqlParameter构造函数,该构造函数允许您指定参数类型在我删除sp名称后的参数列表后,我遇到了以下异常:“过程或函数'taivmultibintobuntrasfer'需要参数'@I_vITEMNMBR',但未提供该参数。”我将尝试您告诉我的构造函数。问题可能是符号问题。NVARCHAR为两个字节。smallint为15位,带有符号位。请尝试删除”EXECUTE““text和在sp名称后以text形式列出的参数。另外,我建议您使用SqlParameter构造函数,该构造函数允许您指定参数类型在我删除sp名称后的参数列表后,出现此异常:“过程或函数'TaivMultibinToBurnAsfer'需要参数'@I_vITEMNMBR',但未提供此参数。”我会尝试你告诉我的构造函数。我用我创建的另一个SP测试了这段代码,并进行了一些测试,它工作正常。你是说我应该在我的c函数上硬编码?问题似乎与“sp_executesql”有关,我无法避免任何参数。但我不知道如何强制实体框架不使用它,并像您在示例中所写的那样运行原始查询。ExecuteSqlCommand实际上只是事务中SqlCommand的EF包装器。您正在设置的参数是针对整个命令的,它可以执行任意数量的语句。谢谢,您为我指明了正确的方向。我用SqlCommand修改了代码,我可以让它正常工作。下次如果我必须运行SP,我将使用旧的、可靠的SqlCommand,而不是EFCore新特性。直到现在,我只有在需要做更复杂的事情时才会遇到问题。没问题。我认为您不必使用SqlCommand返回。这将完成所有步骤,对您有用,并将其包装到事务中并管理连接状态。我使用另一个SP测试了此代码,该SP是我为进行一些测试而创建的,它工作正常。你是说我应该在我的c函数上硬编码?问题似乎与“sp_executesql”有关,我无法避免任何参数。但我不知道如何强制实体框架不使用它,并像您在示例中所写的那样运行原始查询。ExecuteSqlCommand实际上只是事务中SqlCommand的EF包装器。您正在设置的参数是针对整个命令的,它可以执行任意数量的语句。谢谢,您为我指明了正确的方向。我用SqlCommand修改了代码,我可以让它正常工作。下次如果我必须运行SP,我将使用旧的、可靠的SqlCommand,而不是EFCore新特性。直到现在,我只有在需要做更复杂的事情时才会遇到问题。没问题。我认为您不必使用SqlCommand返回。这将为您完成所有步骤,并将其包装到事务中,并管理连接状态。