.NET: How to insert XML document into SQL Server

后端 未结 4 477
野性不改
野性不改 2021-01-04 18:27

I want to insert arbitrary XML into SQL Server. The XML is contained in an XmlDocument object.

The column I want to insert into is either nvarchar

相关标签:
4条回答
  • 2021-01-04 18:29

    The simplest solution is to use the OuterXml attribute of the document. I came across your question while trying to solve the problem under the condition that I could not executed a stored procedure. OuterXml returns the string of text you were expecting to get from .Value or .ToString()

    void SaveXmlToDatabase(DbConnection connection, 
          XmlDocument xmlToSave, 
          String tableName, String columnName); 
    { 
       String sql = "INSERT INTO "+tableName+" ("+columnName+")  
              VALUES ('"+xmlToSave.OuterXml+"')"; 
    
       using (DbCommand command = connection.CreateCommand()) 
       { 
          command.CommandText = sql; 
    
          DbTransaction trans = connection.BeginTransaction(); 
          try 
          { 
             command.ExecuteNonQuery(); 
             trans.Commit(); 
          } 
          catch (Exception) 
          { 
             trans.Rollback(); 
             throw; 
          } 
       } 
    } 
    
    0 讨论(0)
  • 2021-01-04 18:35

    You have to use an SqlParameter. I would recommend doing it like that:

    command.Parameters.Add(
       new SqlParameter("@xml", SqlDbType.Xml) 
           {Value = new SqlXml(new XmlTextReader(xmlToSave.InnerXml
                           , XmlNodeType.Document, null)) })
    

    and the SQL should look like:

    String sql = "INSERT INTO "+tableName+" ("+columnName+") VALUES (@xml)";
    

    And since the first child is always the xml node, you can replace the encoding with the following statement.

    xmlToSave.FirstChild.InnerText = "version=\"1.0\" encoding=\"UTF-16\"";
    

    All in all it would look like that:

    void SaveXmlToDatabase(DbConnection connection,
          XmlDocument xmlToSave,
          String tableName, String columnName);
    {
       String sql = "INSERT INTO "+tableName+" ("+columnName+") VALUES (@xml)";
    
       using (DbCommand command = connection.CreateCommand())
       {
          xmlToSave.FirstChild.InnerText = "version=\"1.0\" encoding=\"UTF-16\"";             
          command.CommandText = sql;
          command.Parameters.Add(
            new SqlParameter("@xml", SqlDbType.Xml) 
               {Value = new SqlXml(new XmlTextReader(xmlToSave.InnerXml
                           , XmlNodeType.Document, null)) });
    
    
          DbTransaction trans = connection.BeginTransaction();
          try
          {
             command.ExecuteNonQuery();
             trans.Commit();
          }
          catch (Exception)
          {
             trans.Rollback();
             throw;
          }
       }
    }
    
    0 讨论(0)
  • 2021-01-04 18:37

    Just wanted to add an SQLConnection equivalent to Jonathan Overholt's solution:

    private void StoreXMLInDatabase(XmlDocument doc)
    {
        // xmlvalue is the name of the database column you want to insert into
        String sql = "INSERT INTO [tablename] (xmlvalue) VALUES (@xmlvalue)";
        // In order to read out you connection string from app.config, remember first to add a reference to System.Configuration in references,
        // and set using System.Configuration; in the top of the file
        string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;  
        using (SqlConnection conn = new SqlConnection(connString))
        {
            if (conn.State == ConnectionState.Closed)
            {
                conn.Open();
            }
            SqlTransaction transaction = conn.BeginTransaction();
            try
            {
                // Remember to specify the SqlTransaction *name* (transaction)
                SqlCommand cobj = new SqlCommand(sql, conn, transaction);
                cobj.CommandText = sql;
                cobj.Parameters.AddWithValue("xmlvalue", new SqlXml(new XmlNodeReader(doc)));
                cobj.ExecuteNonQuery();
                transaction.Commit();
            }
            catch (SqlException ex)
            {
                //2627 = inserting duplicate key fail. Lets the procedure continue although an identity insert fail occurs
                if (ex.Number == 2627)
                {
                    transaction.Rollback();
                }
            }
        } // end using
    }
    

    Tested OK in Visual studio 2017 and 2013 with .net up to version 4.6.2, and against MS SQL Server 2008 R2, 2012 and 2016

    If an identity insert fail and you want to stop the procedure then, just insert a line after transaction.Rollback() like this:

    throw;
    

    Or you can stop the procedure in any circumstance by putting the transaction.Rollback(); and throw; lines just outside the conditional (the if)

    0 讨论(0)
  • 2021-01-04 18:54

    Better late than never... I think you're looking for something like this:

    void SaveXmlToDatabase(DbConnection connection,
          XmlDocument xmlToSave,
          String tableName, String columnName)
    {
       String sql = "INSERT INTO "+tableName+" ("+columnName+") 
              VALUES (@XmlVal)";
    
       using (DbCommand command = connection.CreateCommand())
       {
          command.CommandText = sql;
          command.Parameters.AddWithValue("XmlVal", new SqlXml(new XmlNodeReader(xmlToSave)));
    
          DbTransaction trans = connection.BeginTransaction();
          try
          {
             command.ExecuteNonQuery();
             trans.Commit();
          }
          catch (Exception)
          {
             trans.Rollback();
             throw;
          }
       }
    }
    

    The XmlNodeReader object traverses and properly encodes the XmlDocument (or any other XmlNode), and the SqlXml object encapsulates that into the SqlDbType suitable for use with the parameter. This is safer and probably more efficient than using a string intermediary.

    0 讨论(0)
提交回复
热议问题