Send to printer
asp.net C#
 

Stored Procedure (make sure you change the last line so that only the database role you want is allowed to execute!):


GO

SET QUOTED_IDENTIFIER ON

GO

SET ANSI_NULLS ON

GO


PRINT 'Creating stored procedure dbo.Insert_Update_Customers_sp...'

GO

IF OBJECT_ID('dbo.Insert_Update_Customers_sp') IS NOT NULL
   DROP PROCEDURE dbo.Insert_Update_Customers_sp

GO

CREATE PROCEDURE dbo.Insert_Update_Customers_sp(
     @namespaceUri       NVARCHAR(255)
    ,@source_data_xml     NTEXT
)

AS

BEGIN

/*****************************************************************/
-- PROCEDURE: dbo.Insert_Update_Customers_sp

-- PURPOSE: Inserts or updates customer records based on source.xml
-- Information is passed in three parameters
-- the first parameter, @namespaceUri, contains an optional namespaceURI
-- (exclusive of the prefix used).  This is needed to construct the
-- call to sp_xml_preparedocument so that QNames can be used in the
-- XPath expressions for OPENXML().  Currently not used.
-- @source_data_xml contains the data for the document itself.
-- no output results are needed, but success is returned.

-- INPUT:
--       ,@namespaceUri NVARCHAR(255) -- namespaceURI of the xml document
--       ,@source_data_xml   NTEXT -- XML Document for operation


-- OUTPUT: None

-- CREATED:
-- DATE                 AUTHOR
-- 03/02/2005           Mike Sharp

-- UPDATED:
-- DATE                 AUTHOR


/*****************************************************************/

SET NOCOUNT ON

/**********************************************************/
-- Declare Local Variables
/**********************************************************/

DECLARE @idoc                       INT
       ,@sql_error                  INT
       ,@return_code                INT
       ,@error_message              VARCHAR(1000)
       ,@stored_procedure_name      SYSNAME
       ,@tran_count                 INT
       ,@Namespace_Root_Node        NVARCHAR(300)
       ,@Last_Modified_Date         DATETIME
       ,@Last_Modified_User         NVARCHAR(128)


/**********************************************************/
-- seed local variables
/**********************************************************/

SELECT @sql_error = 0
      ,@return_code = 0
      ,@stored_procedure_name = OBJECT_NAME(@@PROCID)
      ,@tran_count = @@TRANCOUNT
      ,@Namespace_Root_Node = '<customerData xmlns:my="' + @namespaceUri + '"/>'
      -- Note that this implementation does not need namespaces. 
      -- This is how it would be constructed if they were used.
      -- The @Namespace_Root_Node would be passed as the last parameter
      -- to dbo.sp_xml_preparedocument.

/**********************************************************/
-- Create an Internal representation of the XML document.
-- from the @source_data_xml
/**********************************************************/

EXECUTE dbo.sp_xml_preparedocument @idoc  OUTPUT, @source_data_xml

/**********************************************************/
-- If an error was encountered while executing the stored
-- procedure go to the on error section
/**********************************************************/

IF @@ERROR <> 0

   BEGIN

      SELECT @sql_error = -1
            ,@error_message = @stored_procedure_name + ': ' + 'error executing sp_xml_preparedocument against the xml document'
            ,@return_code = 60100

      GOTO on_error

   END

/**********************************************************/
-- extract form values from xml document
/**********************************************************/


-- First, insert new records

INSERT INTO Customers

SELECT   CustomerID 
        ,CompanyName
        ,ContactName
        ,ContactTitle
        ,Address   
        ,City       
        ,Region     
        ,PostalCode 
        ,Country   
        ,Phone     
        ,Fax       

  FROM OPENXML(@idoc,'/customerData/customer',1)
  WITH ( CustomerID                 NCHAR(5)        '@id'
        ,CompanyName                NVARCHAR(40)    'companyInfo/nameInfo/companyName'
        ,ContactName                NVARCHAR(50)    'companyInfo/nameInfo/contactName/@name'
        ,ContactTitle               NVARCHAR(50)    'companyInfo/nameInfo/contactName/@title'
        ,Address                    NVARCHAR(60)    'companyInfo/companyDetails/address/@street'
        ,City                       NVARCHAR(15)    'companyInfo/companyDetails/address/@city'
        ,Region                     NVARCHAR(15)    'companyInfo/companyDetails/address/@state'
        ,PostalCode                 NVARCHAR(10)    'companyInfo/companyDetails/address/@zip'
        ,Country                    NVARCHAR(15)    'companyInfo/companyDetails/address/@country'
        ,Phone                      NVARCHAR(24)    'companyInfo/companyDetails/phone/busPhone/@busLine'
        ,Fax                        NVARCHAR(24)    'companyInfo/companyDetails/phone/busFax/@busLine'
       )
      
WHERE   CustomerID NOT IN (SELECT CustomerID FROM Customers)

-- Next, Update existing records

UPDATE Customers

SET      Customers.CompanyName  =   myXml.CompanyName
        ,Customers.ContactName  =   myXml.ContactName
        ,Customers.ContactTitle =   myXml.ContactTitle
        ,Customers.Address      =   myXml.Address   
        ,Customers.City         =   myXml.City       
        ,Customers.Region       =   myXml.Region     
        ,Customers.PostalCode   =   myXml.PostalCode 
        ,Customers.Country      =   myXml.Country   
        ,Customers.Phone        =   myXml.Phone     
        ,Customers.Fax          =   myXml.Fax       

  FROM OPENXML(@idoc,'/customerData/customer',1)
  WITH ( CustomerID                 NCHAR(5)        '@id'
        ,CompanyName                NVARCHAR(40)    'companyInfo/nameInfo/companyName'
        ,ContactName                NVARCHAR(50)    'companyInfo/nameInfo/contactName/@name'
        ,ContactTitle               NVARCHAR(50)    'companyInfo/nameInfo/contactName/@title'
        ,Address                    NVARCHAR(60)    'companyInfo/companyDetails/address/@street'
        ,City                       NVARCHAR(15)    'companyInfo/companyDetails/address/@city'
        ,Region                     NVARCHAR(15)    'companyInfo/companyDetails/address/@state'
        ,PostalCode                 NVARCHAR(10)    'companyInfo/companyDetails/address/@zip'
        ,Country                    NVARCHAR(15)    'companyInfo/companyDetails/address/@country'
        ,Phone                      NVARCHAR(24)    'companyInfo/companyDetails/phone/busPhone/@busLine'
        ,Fax                        NVARCHAR(24)    'companyInfo/companyDetails/phone/busFax/@busLine'
       )
      
       myXml

WHERE    Customers.CustomerID   =   myXml.CustomerID   

 

 


/**********************************************************/
-- Remove the document
/**********************************************************/

EXECUTE dbo.sp_xml_removedocument @iDoc

/**********************************************************/
-- If an error was encountered while executing the stored
-- procedure, rollback transaction, go to the on error section
/**********************************************************/

IF @@ERROR <> 0

   BEGIN

      SELECT @sql_error = -1
            ,@error_message = @stored_procedure_name + ': ' + 'error executing sp_xml_removedocument against the xml document'
            ,@return_code = 60300

      GOTO on_error

   END


/**********************************************************/
-- on error section
-- log event and return @return code value
/**********************************************************/


on_error:

   IF @sql_error <> 0

      BEGIN

         SELECT  @error_message = 'Procedure ' + @stored_procedure_name + ' - ' + @error_message + ' ReturnCode = ' + CONVERT(VARCHAR(10), @return_code )
         EXECUTE master.dbo.xp_logevent @return_code, @error_message, ERROR

         RETURN(@return_code)

      END


END


GO

SET QUOTED_IDENTIFIER OFF

GO

SET ANSI_NULLS OFF

GO

/**************************************************/
-- Grant execute permissions on the form
--  stored procedure to the application role
/**************************************************/

GRANT EXECUTE ON dbo.Insert_Update_Customers_sp TO public

GO


==================================================================

 

Console Application in C# to do the work.  Download and install SQL XML 3.0, and add it as a reference in the project.  Then use this code to test/run it:

using System;
using System.Text;
using System.Xml;
using Microsoft.Data.SqlXml;

namespace basicDOM
{
      /// <summary>
      /// Summary description for Class1.
      /// </summary>
      class Class1
      {
            static XmlDocument xmlDoc = new XmlDocument();

            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
                  XmlDocument xml = new XmlDocument();
                  xml.PreserveWhitespace = true;
                  xml.Load("customerdata.xml");
                  Console.WriteLine(xml.OuterXml);
                  // Converting our XML into a string forces it to be UTF-16, so we want to
                  // remove the processing instruction that used to say UTF-8
                  // Of course, it would be best to explicitly handle the encoding.
                  bool bUpdate = UpdateDb(xml.DocumentElement.OuterXml, "");
                  Console.WriteLine("database updated: " + bUpdate.ToString());
                  string pause = Console.ReadLine();
            }

            /// <summary>
            /// Helper function to update the database.  Use SqlXmlCommand object and SqlXmlParameter object
            /// to execute a sproc.
            /// </summary>
            /// <param name="xml">XML node representing the top level of the document fragment used to update
            /// the Forms database. </param>
            /// <param name="xmlns">The namespaceURI, if any</param>
            /// <returns>boolean</returns>
            static bool UpdateDb(string xml, string xmlns)
            {
                  SqlXmlParameter SourceNamespace;
                  SqlXmlParameter SourceDataXml;
                  try
                  {
                        SqlXmlCommand cmd = new SqlXmlCommand("Provider=SQLOLEDB;Server=DevVsMichaels03;database=Northwind;Trusted_Connection=yes;");
                        cmd.CommandType = SqlXmlCommandType.Sql;
                        cmd.CommandText = "Execute Insert_Update_Customers_sp ?, ?";
                        SourceNamespace = cmd.CreateParameter();
                        SourceNamespace.Name = "namespaceUri";
                        SourceNamespace.Value = xmlns;
                        SourceDataXml = cmd.CreateParameter();
                        SourceDataXml.Name = "source_data_xml";
                        SourceDataXml.Value = xml;
                        try
                        {
                              cmd.ExecuteNonQuery();
                        }
                        catch (Exception ex)
                        {
                              Console.WriteLine("Exception during ExecuteNonQuery...Update failed: " + ex.Message + "[" + ex.Source + "]" + ex.StackTrace);
                              return false;
                        }
                  }
                  catch(Exception ex)
                  {
                        Console.WriteLine("Could not construct SqlXmlCommand: " + ex.Message + "[" + ex.Source + "]" + ex.StackTrace);
                        return false;
                  }
                  return true;


            }

      }
}

 

XML file tried to load
--------------------------------

<?xml version="1.0" encoding="UTF-8" ?> 
<customerData>
      <customer id="WID10">
            <companyInfo>
            <nameInfo>
                 <companyName>Widgets Inc.</companyName>
                 <contactName name="John Doe" title="President" />
            </nameInfo>
            <companyDetails>
                 <address street="1234 Anywhere" city="Pinetop" state="AZ" zip="85244" country="USA" />
                 <phone>
                 <busPhone busLine="520 123-1234" mobile="520 123-1238" />
                  <busFax busLine="520 123-1235" />
                </phone>
            </companyDetails>
          </companyInfo>
      </customer>
      <customer id="CarpA">
            <companyInfo>
                  <nameInfo>
                        <companyName>Carpet Inc.</companyName>
                        <contactName name="Jane Doe" title="President" />
                  </nameInfo>
                  <companyDetails>
                        <address street="1234 Red Carpet St." city="Phoenix" state="AZ" zip="85999" country="USA" />
                        <phone>
                              <busPhone busLine="480 123-1234" mobile="480 123-1238" />
                              <busFax busLine="480 123-1235" />
                        </phone>
                  </companyDetails>
            </companyInfo>
      </customer>
</customerData>

-------------------------------
Load with error
------------------


Insert_Update_Customers_sp 'http://tempuri.org/customers.xsd','<?xml version="1.0"?>
<customerData xmlns="http://tempuri.org/customers.xsd">
    <customer id="WID10">
        <companyInfo>
            <nameInfo>
                <companyName>Widgets Inc.</companyName>
                <contactName name="John Doe" title="President" />
            </nameInfo>
            <companyDetails>
                <address street="1234 Anywhere" city="Pinetop" state="AZ" zip="85244" country="USA" />
                <phone>
                    <busPhone busLine="520 123-1234" mobile="520 123-1238" />
                    <busFax busLine="520 123-1235" />
                </phone>
            </companyDetails>
        </companyInfo>
    </customer>
    <customer id="CarpA">
        <companyInfo>
            <nameInfo>
                <companyName>Carpet Inc.</companyName>
                <contactName name="Jane Doe" title="President" />
            </nameInfo>
            <companyDetails>
                <address street="1234 Red Carpet St." city="Phoenix" state="AZ" zip="85999" country="USA" />
                <phone>
                    <busPhone busLine="480 123-1234" mobile="480 123-1238" />
                    <busFax busLine="480 123-1235" />
                </phone>
            </companyDetails>
        </companyInfo>
    </customer>
</customerData>'

--------------------------------------------
reasonse for error


the XML you posted earlier did not have the namespace...that's why it's not adding the records.  You need to modify the sproc with:

EXECUTE dbo.sp_xml_preparedocument @idoc  OUTPUT, @source_data_xml, @Namespace_Root_Node

and then you have to qualify every namespaced node in each of the XPath expressions in the open XML.

In XML it's important to realize that namespaces are significant.


Posted by Mike Sharp