4

我有一个帐户创建过程,基本上当用户注册时,我必须在多个表中进行条目,即用户、个人资料、地址。用户表中有 1 个条目,配置文件中有 1 个条目,地址表中有 2-3 个条目。因此,最多将有 5 个条目。我的问题是我应该将它的 XML 传递给我的存储过程并在那里解析它,还是应该在我的 C# 代码中创建一个事务对象,保持连接打开并在循环中一一插入地址?

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

4

4 回答 4

6

没有冒犯,但你想多了。

收集您的信息,当您拥有所有信息时,创建一个事务并一次插入一个新行。这里没有性能影响,因为事务将是短暂的。

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

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

希望这可以帮助。

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

于 2012-04-24T09:45:48.600 回答
5

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

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

最好的方法是在存储过程中使用表参数。在.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。

于 2012-04-24T10:07:16.690 回答
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(对象关系映射)库。他们消除了与数据库交谈的痛苦并为您处理。

于 2012-04-24T11:01:22.890 回答
0

例如假设您的 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   
于 2012-04-24T09:49:35.077 回答