4

I have an account creation process and basically when the user signs up, I have to make entries in mutliple tables namely User, Profile, Addresses. There will be 1 entry in User table, 1 entry in Profile and 2-3 entries in Address table. So, at most there will be 5 entries. My question is should I pass a XML of this to my stored procedure and parse it in there or should I create a transaction object in my C# code, keep the connection open and insert addresses one by one in loop?

How do you approach this scenario? Can making multiple calls degrade the performance even though the connection is open?

Jack
  • 7,433
  • 22
  • 63
  • 107
  • I would certainly go the xml way. But you run the whole stored procedure under a transaction so that error will rollback. – Deeptechtons Apr 24 '12 at 09:41

4 Answers4

6

No offence, but you're over thinking this.

Gather your information, when you have it all together, create a transaction and insert the new rows one at a time. There's no performance hit here, as the transaction will be short lived.

A problem would be if you create the transaction on the connection, insert the user row, then wait for the user to enter more profile information, insert that, then wait for them to add address information, then insert that, DO NOT DO THIS, this is a needlessly long running transaction, and will create problems.

However, your scenario (where you have all the data) is a correct use of a transaction, it ensures your data integrity and will not put any strain on your database, and will not - on it's own - create deadlocks.

Hope this helps.

P.S. The drawbacks with the Xml approach is the added complexity, your code needs to know the schema of the xml, your stored procedure needs to know the Xml schema too. The stored procedure has the added complexity of parsing the xml, then inserting the rows. I really don't see the advantage of the extra complexity for what is a simple short running transaction.

Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
  • 1
    Agreed, XML is not a standard way to do this, and I would never recommend it. There are frameworks and technologies to deal with this, and all you need is a short-lived transaction in your BLL/DAL and a few simple queries – Kieren Johnstone Apr 24 '12 at 09:52
  • @Thanks Binary Worrier. Very nice but Romil's answer is also very good. I accepted that since it too looks very promising. – Jack Apr 24 '12 at 12:43
5

If you want to insert records in multiple table then using XML parameter is a complex method. Creating Xml in .net and extracting records from xml for three diffrent tables is complex in sql server.

Executing queries within a transaction is easy approach but some performance will degrade there to switch between .net code and sql server.

Best approach is to use table parameter in storedprocedure. Create three data table in .net code and pass them in stored procedure.

--Create Type TargetUDT1,TargetUDT2 and TargetUDT3 for each type of table with all fields which needs to insert

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

--Now write down the sp in following manner.

 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

In .Net, Create three data table and fill the value, and call the sp normally.

Romil Kumar Jain
  • 20,239
  • 9
  • 63
  • 92
0

For example assuming your xml as below

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

this would be your stored procedure

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

where this would provide idoc variable value and @doc is the input to the stored procedure

DECLARE @idoc INT

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

using similar technique you would run 3 inserts in single stored procedure. Note that it is single call to database and multiple address elements will be inserted in single call to this stored procedure.

Update

just not to mislead you here is a complete stored procedure for you do understand what you are going to do

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   
Community
  • 1
  • 1
Deeptechtons
  • 10,945
  • 27
  • 96
  • 178
  • You must always remove the document handle when you are done, as per http://msdn.microsoft.com/en-us/library/ms187367.aspx – Kieren Johnstone Apr 24 '12 at 09:51
  • @KierenJohnstone yes off course. I thought the OP has knowledge to do it. If not i shall add it for more complete answer – Deeptechtons Apr 24 '12 at 09:53
  • A long time ago this is something I might have done. The problem is that it assumes that there are going to be performance issues and forces complexities in your database and your applications data layer. – Bronumski Apr 24 '12 at 10:44
  • @Deeptechtons: Why have you used ntext in input parameter? Why not use XML datatype if at all, and parse it using query function. – Jack Apr 24 '12 at 12:42
  • @TomKaufmann without knowing OP has knowledge of XML extensions for SQL server i would lead him to another learning loop. Just for sake of clarity and how it could have been done i had to user NTEXT. Got it? btw i don't understand why people downvote without a reason for it!! – Deeptechtons Apr 25 '12 at 05:11
  • @Deeptechtons: I am the OP and if I ask a question about XML obviously I know about XML. Got it? Regarding downvotes, I am not sure :) – Jack Apr 25 '12 at 12:31
0

Have you noticed any performance problems, what you are trying to do is very straight forward and many applications do this day in day out. Be careful not to be drawn into any premature optimization.

Database inserts should be very cheep, as you have suggested create a new transaction scope, open you connection, run your inserts, commit the transaction and finally dispose everything.

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();
}

Bundling all your logic into a stored procedure and using XML gives you added complications, you will need to have additional logic in your database, you now have to transform your entities into an XML blob and you code has become harder to unit test.

There are a number of things you can do to make the code easier to use. The first step would be to push your database logic into a reusable database layer and use the concept of a repository to read and write your objects from the database.

You could of course make your life a lot easier and have a look at any of the ORM (Object-relational mapping) libraries that are available. They take away the pain of talking to the database and handle that for you.

Bronumski
  • 14,009
  • 6
  • 49
  • 77