【问题标题】:Problem with logic in passing data to a stored procedure EF in C#在 C# 中将数据传递给存储过程 EF 的逻辑问题
【发布时间】:2019-03-14 17:50:53
【问题描述】:

我在 SQL Server 数据库中有一个包含 13 个参数的存储过程。在我的 C# 应用程序中,我需要向该存储过程插入数据,并且我能够一次插入 1 个值,但我需要能够插入多个值,例如 5 个或 10 个或更多。我有 5 个数组,它们将有许多值插入到该存储过程中,但如果数组的值超过 1 个,则不插入,我认为我的循环没有正确完成。

请看下面。

将为存储过程创建方法的类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BarcodeReceivingApp.Persistence;
using BarcodeReceivingApp.Persistence.Repositories;

namespace BarcodeReceivingApp.Functionality
{
    public class StoredProcedureInsert
    {
        private readonly BarcodeReceivingFootPrintDbContext _barcodeReceivingFootPrintDbContext = new BarcodeReceivingFootPrintDbContext();

        public void CallManualBlindBarcodeParsingEventRequestFootPrintProcedure(decimal actualPackagedAmount, int actualPackagedPackId, string lotLookupCode,
            int warehouseId, int materialId, string vendorLotLookupCode, DateTime vendorLotManufactureDate, 
            DateTime vendorLotExpirationDate, int shipmentId, decimal netWeight, 
            decimal grossWeight, string serialLookupCode, string licensePlateLookupCode)
        {
            _barcodeReceivingFootPrintDbContext.Database
                .ExecuteSqlCommand("EXEC noram_reporting.ManualBlindBarcodeParsingEventRequest " +
                                   "@ActualPackagedAmount, @ActualPackagedPackId, @LotLookupCode, @WarehouseId, @MaterialId, @VendorLotLookupCode," +
                                   "@VendorLotManufactureDate, @VendorLotExpirationDate, @ShipmentId, @netWeight, @grossWeight, @serialLookupCode, @licensePlateLookupCode",
                    new SqlParameter("@ActualPackagedAmount", actualPackagedAmount),
                    new SqlParameter("@ActualPackagedPackId", actualPackagedPackId),
                    new SqlParameter("@LotLookupCode", lotLookupCode),
                    new SqlParameter("@WarehouseId", warehouseId),
                    new SqlParameter("@MaterialId", materialId),
                    new SqlParameter("@VendorLotLookupCode", vendorLotLookupCode),
                    new SqlParameter("@VendorLotManufactureDate", vendorLotManufactureDate),
                    new SqlParameter("@VendorLotExpirationDate", vendorLotExpirationDate),
                    new SqlParameter("@ShipmentId", shipmentId),
                    new SqlParameter("@netWeight", netWeight),
                    new SqlParameter("@grossWeight", grossWeight),
                    new SqlParameter("@serialLookupCode", serialLookupCode),
                    new SqlParameter("@licensePlateLookupCode", licensePlateLookupCode)
                    );
        }
    }
}

然后我在这里调用该方法来插入每个参数

private void SendStoredProcedureDataToFootPrint()
{
    var lotList = _connection.ParseLot();
    var netWeightList = _connection.ParseNetWeight();
    var grossWeightList = _connection.ParseGrossWeight();
    var serialNumberList = _connection.ParseSerialNumber();
    var material = _unitOfWork.Shipments.GetLastShipmentMaterialEntry();
    var scanCounts = _connection.CountReceivingBarcodeEntries();
    var packagingId = _unitOfWork.Materials.GetPackagingId();
    var warehouse = _unitOfWork.Warehouses.GetWarehouseIdQuery();
    var shipment = _unitOfWork.Shipments.GetLastShipmentIdEntry();
    var licensePlate = _unitOfWork.LicensePlates.GetLastCreatedLicensePlate();

    try
    {
        for (var i = 0; i < _connection.GetBarcodeList().Count ; i++)
        {

            _storedProcedureInsert.CallManualBlindBarcodeParsingEventRequestFootPrintProcedure(scanCounts, packagingId, lotList[i], warehouseId: warehouse, materialId: 5785,
                vendorLotLookupCode: lotList[i], vendorLotManufactureDate: DateTime.Now,
                vendorLotExpirationDate: DateTime.Now, shipmentId: shipment,
                netWeight: Convert.ToDecimal(netWeightList[i]) / 100,
                grossWeight: Convert.ToDecimal(grossWeightList[i]) / 100,
                serialLookupCode: serialNumberList[i], licensePlateLookupCode: licensePlate);
        }
    }
    catch (Exception exception)
    {
        MetroMessageBox.Show(null, exception.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        throw;
    }
}

所以,就像我说的那样,如果我为每个参数插入 1 个数据,但如果 lotlist、netweightlist、grossweightlist 和 serialnumberlist 数组有超过 1 个数据,它将不会发送到存储过程。

所以我们的目标是插入数据,我需要插入的记录很多并不重要,一次可以插入一条或多条。

在 stackoverflow 或 google 等其他问题中找不到很好的解决方案。

【问题讨论】:

  • 您好。 1) 如果需要传入数组,则需要查看表值参数。我不知道如何在 EF 的上下文中使用它们,但这就是您在 SQL Server 中的操作方式(或者传入 XML 或分隔列表)。 2) 请停止使用“clrstoredprocedure”标签。这是一个不好的标签,它指的是不是“使用.NET调用存储过程”的东西;它用于在 SQL Server 中使用 .NET(即 SQLCLR;请阅读:Stairway to SQLCLR Level 1: What is SQLCLR?)。
  • 你能给我看一个表值参数的例子吗?
  • 您可以查看我对不涉及 EF 的类似问题的回答:Pass Dictionary<string,int> to Stored Procedure T-SQL。我希望这会有所帮助:-)。

标签: sql-server entity-framework c#-4.0 entity-framework-migrations


【解决方案1】:

请使用表值参数来处理这类场景。但是您必须将数据转换为 DataTable。每个数组都有对应的数据表。

我想给你一个想法。

  1. 将每个 C# 列表转换为 DataTable。

    将每个数组(例如,serialNumberList 转换为 DataTable。)(如果它只是原始数据,那么只有一列会对应,如果它是对象则完整的行。在这种情况下,对于每一行:每个单元格对应于 C# 对应的数据对象数据成员。)

  2. 在 SQL Server 中创建“可编程性”下的数据类型,它将从您的 C# 代码接收这些数据表。此数据类型将具有与 C# 结构中相同的 SQL 单个类型完全相同的数据。

  3. 无论您在循环内做什么(关于转换或做一些数学运算,甚至在传递到 SQL 之前,都在同一个列表中进行。最终,在数据已经处理后将数据传递给 SQL)。

  4. 在将数据传递给 SQL 之前,您应该知道数据必须作为表值参数传递。所以它的数据类型必须选择为SQLDataType.Structured。

  5. 对于每个非列表数据项,不要创建任何数据表。使用 .NET 中的 SQL 原生数据类型直接传递它。

如果您以这种方式解决问题,请告诉我。我敢肯定,它会成功的。 此外,如果您想进一步了解如何传递复杂结构/简单原生数据类型 Array 或 Object Array,请参考以下链接。

T-SQL - Insert Data into Parent and Child Tables.

【讨论】:

  • 谢谢,我会检查你的回答,然后告诉你结果如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-22
  • 2019-04-23
  • 2012-09-01
  • 2015-08-20
  • 2017-09-07
  • 2011-07-21
相关资源
最近更新 更多