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

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

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

如果要在多个表中插入记录,则使用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。

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

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

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

但是,您的方案(您拥有所有数据)是正确使用事务,它确保您的数据完整性,不会对您的数据库造成任何压力,也不会 – 在它自己 – 上创建死锁。

希望这可以帮助。

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

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

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

 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,并且代码变得越来越难以进行unit testing。

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

您当然可以让您的生活更轻松,并查看可用的任何ORM(对象关系映射)库。 它们消除了与数据库交谈的痛苦并为您处理。

例如假设你的xml如下

        

这将是您的存储过程

 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