我有一个帐户创建过程,基本上当用户注册时,我必须在多个表格中输入用户,个人资料,地址。 User表中有1个条目,Profile中有1个条目,Address表中有2-3个条目。所以,最多会有5个条目。我的问题是我应该将这个XML传递给我的存储过程并在那里解析它,还是应该在我的C#代码中创建一个事务对象,保持连接打开并逐个插入地址?
您如何处理这种情况?即使连接打开,是否可以进行多次调用会降低性能?
答案 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