通过存储过程插入多个sql行

时间:2013-06-17 18:56:54

标签: c# .net sql sql-server

我看了一些相关主题,但我的问题没有得到很好的回答:

在我的Web应用程序的代码中运行存储过程时,我有以下类型的设置。问题是我现在面临着插入多个产品的可能性,我想在一个ExecuteNonQuery中完成所有操作,而不是foreach loop并且运行n次。

我不确定如何使用我当前的设置执行此操作,或者是否可以执行此操作。

代码应该有点自我解释,但如果需要澄清,请告诉我。感谢。

SqlDatabase database = new SqlDatabase(transMangr.ConnectionString);
DbCommand commandWrapper = StoredProcedureProvider.GetCommandWrapper(database, "proc_name", useStoredProc);

database.AddInParameter(commandWrapper, "@ProductID", DbType.Int32, entity._productID);
database.AddInParameter(commandWrapper, "@ProductDesc", DbType.String, entity._desc);
...more parameters...


Utility.ExecuteNonQuery(transMangr, commandWrapper);

PROC

ALTER PROCEDURE [dbo].[Products_Insert]
-- Add the parameters for the stored procedure here
         @ProductID int,
         @Link      varchar(max)
         @ProductDesc          varchar(max)
         @Date          DateTime
    AS BEGIN

SET NOCOUNT ON;


INSERT INTO [dbo].[Prodcuts]
    ( 
        [CategoryID],
        [Link],
        [Desc],
        [Date]
    )
VALUES
    (
        @ProductID,
        @Link,
        @ProductDesc,
        @Date
    )

END

4 个答案:

答案 0 :(得分:1)

您应该在循环中运行存储过程。只要确保你很少提交,而不是在每次插入后提交。

对于替代方案,您已经找到了有关加载数据的讨论。

就个人而言,我喜欢insert into myTable (select *, literalValue from someOtherTable);形式的SQL批量插入 但在你的情况下,这可能不会做。

答案 1 :(得分:0)

您可以将所有数据作为表值参数传递 - MSDN对此有一个很好的解释here

以下内容应该有效

CREATE TABLE dbo.tSegments (

SegmentID BIGINT NOT NULL CONSTRAINT pkSegment PRIMARY KEY CLUSTERED,
SegCount BIGINT NOT NULL

);

CREATE TYPE dbo.SegmentTableType AS TABLE ( SegmentID BIGINT NOT NULL );

CREATE PROCEDURE dbo.sp_addSegments

  @Segments dbo.SegmentTableType READONLY

AS

BEGIN      MERGE INTO dbo.tSegments AS tSeg

USING @Segments AS S
ON tSeg.SegmentID = S.SegmentID
WHEN MATCHED THEN UPDATE SET T.SegCount = T.SegCount + 1
WHEN NOT MATCHED THEN INSERT VALUES(tSeg.SegmentID, 1);

END

答案 2 :(得分:0)

为循环外的命令定义commandWrapper和参数,然后在循环中只分配参数值并执行proc。

SqlDatabase database = new SqlDatabase(transMangr.ConnectionString);
DbCommand commandWrapper = StoredProcedureProvider.GetCommandWrapper(database, "proc_name", useStoredProc);

database.AddInParameter(commandWrapper, "@ProductID", DbType.Int32 );
database.AddInParameter(commandWrapper, "@ProductDesc", DbType.String);
...more parameters...

foreach (var entity in entitties)
{
    database.SetParameterValue(commandWrapper, "@ProductID",entity._productID);
    database.SetParameterValue(commandWrapper, "@ProductDesc",entity._desc);
    //..more parameters...
    Utility.ExecuteNonQuery(transMangr, commandWrapper);
}

答案 3 :(得分:0)

从纯粹的处理方式来看并不理想,但是有时会受到框架和库的限制,并且您被迫以某种方式调用存储过程,以某种方式绑定参数,并且连接由管理池作为框架的一部分。

在这种情况下,我们发现一种有效的方法是简单地编写带有许多参数的存储过程,这些参数通常是名称,后跟数字,例如@ ProductId1,@ ProductDesc1,@ ProductId2,@ ProductDesc2,直到您决定的数字,可能是32。

您可以使用某种形式的脚本语言来为此生成代码行。

您可以获取存储过程,以首先将所有值插入允许空值的表参数中,然后以类似于Johnv2020的答案的方式对此数据进行批量插入/合并。您可以先删除空行。

通常一次完成效率更高(部分原因是数据库操作本身,部分原因是框架在连接调用过程中的开销等)