你应该进行多次插入调用还是传递XML?

时间:2012-04-24 09:37:56

标签: c# .net sql-server sql-server-2008

我有一个帐户创建过程,基本上当用户注册时,我必须在多个表格中输入用户,个人资料,地址。 User表中有1个条目,Profile中有1个条目,Address表中有2-3个条目。所以,最多会有5个条目。我的问题是我应该将这个XML传递给我的存储过程并在那里解析它,还是应该在我的C#代码中创建一个事务对象,保持连接打开并逐个插入地址?

您如何处理这种情况?即使连接打开,是否可以进行多次调用会降低性能?

4 个答案:

答案 0 :(得分:6)

没有冒犯,但是你在想这个。

收集您的信息,当您将它们放在一起时,创建一个事务并一次插入一个新行。这里没有任何表现,因为交易将是短暂的。

问题是如果你在连接上创建事务,插入用户行,然后等待用户输入更多的配置文件信息,插入它,然后等待它们添加地址信息,然后插入,不要这样做,这是一个不必要的长时间运行的事务,并会产生问题。

但是,您的方案(您拥有所有数据)是正确使用事务,它可以确保您的数据完整性并且不会对您的数据库造成任何压力,也不会 - 在它自己的情况下 - 创建死锁。 / p>

希望这有帮助。

P.S。 Xml方法的缺点是增加了复杂性,您的代码需要知道xml的模式,您的存储过程也需要知道Xml模式。存储过程增加了解析xml,然后插入行的复杂性。我真的没有看到简单的短期运行事务的额外复杂性的优势。

答案 1 :(得分:5)

如果要在多个表中插入记录,则使用XML参数是一种复杂的方法。在.net服务器中创建.net中的Xml并从xml中为三个不同的表提取记录是很复杂的。

在事务中执行查询是一种简单的方法,但是在.net代码和sql server之间切换会降低某些性能。

最好的方法是在storedprocedure中使用table参数。在.net代码中创建三个数据表,并在存储过程中传递它们。

- 为每种类型的表创建类型TargetUDT1,TargetUDT2和TargetUDT3,其中包含需要插入的所有字段

CREATE TYPE [TargetUDT1] AS TABLE
             (
             [FirstName] [varchar](100)NOT NULL,
             [LastName] [varchar](100)NOT NULL,
             [Email] [varchar](200) NOT NULL
             )

- 现在以下列方式写下sp。

 CREATE PROCEDURE AddToTarget(
     @TargetUDT1 TargetUDT1 READONLY,
     @TargetUDT2 TargetUDT2 READONLY,
     @TargetUDT3 TargetUDT3 READONLY)
     AS
 BEGIN
       INSERT INTO [Target1]
       SELECT * FROM @TargetUDT1

       INSERT INTO [Target2]
       SELECT * FROM @TargetUDT2

       INSERT INTO [Target3]
       SELECT * FROM @TargetUDT3
 END

在.Net中,创建三个数据表并填充值,并正常调用sp。

答案 2 :(得分:0)

您是否注意到任何性能问题,您尝试做的事情非常直接,许多应用程序每天都会这样做。小心不要被任何过早的优化所吸引。

数据库插入应该非常简单,因为您建议创建一个新的事务范围,打开连接,运行插入,提交事务并最终处理所有内容。

using (var tran = new TransactionScope())
using (var conn = new SqlConnection(YourConnectionString))
using (var insetCommand1 = conn.CreateCommand())
using (var insetCommand2 = conn.CreateCommand())
{
    insetCommand1.CommandText = \\SQL to insert

    insetCommand2.CommandText = \\SQL to insert

    insetCommand1.ExecuteNonQuery();

    insetCommand2.ExecuteNonQuery();

    tran.Complete();
}

将所有逻辑捆绑到存储过程中并使用XML会增加复杂性,您需要在数据库中使用其他逻辑,现在必须将实体转换为XML blob并且代码变得越来越难以进行单元测试

您可以执行许多操作来使代码更易于使用。第一步是将数据库逻辑推送到可重用的数据库层,并使用存储库的概念从数据库中读取和写入对象。

您当然可以让您的生活更轻松,并查看可用的任何ORM (Object-relational mapping)库。它们消除了与数据库交谈的痛苦,并为您处理。

答案 3 :(得分:-1)

例如假设您的xml如下

<StoredProcedure>
<User>
 <UserName></UserName>
</User>
<Profile>
 <FirstName></FirstName>
</Profile>
<Address>
 <Data></Data>
 <Data></Data>
 <Data></Data>
</Address>
</StoredProcedure>

这将是您的存储过程

INSERT INTO Users (UserName) SELECT(UserName) FROM OPENXML(@idoc,'StoredProcedure/User',2)
WITH ( UserName NVARCHAR(256))

这将提供idoc变量值,而@doc是存储过程的输入

DECLARE @idoc INT

--Create an internal representation of the XML document.        
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc

使用类似的技术,您将在单个存储过程中运行3个插入。请注意,它是对数据库的单个调用,并且将在对此存储过程的单个调用中插入多个地址元素。

更新

只是不要误导你这里是一个完整的存储过程,你明白你将要做什么

USE [DBNAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO  
CREATE PROCEDURE [dbo].[procedure_name]
    @doc [ntext]
WITH EXECUTE AS CALLER
AS
DECLARE @idoc INT  
DECLARE @RowCount INT
SET @ErrorProfile = 0

--Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc

BEGIN TRANSACTION

INSERT INTO Users (UserName)
SELECT UserName FROM OPENXML(@idoc,'StoredProcedure/User',2)
WITH ( UserName NVARCHAR(256) )

-- Insert Address

-- Insert Profile


SELECT @ErrorProfile = @@Error                              

IF @ErrorProfile = 0
    BEGIN
            COMMIT TRAN
    END
ELSE
    BEGIN
            ROLLBACK TRAN
    END

EXEC sp_xml_removedocument @idoc