Sql server .NET:如何将XML文档插入SQL Server
我想将任意XML插入SQL Server。XML包含在Sql server .NET:如何将XML文档插入SQL Server,sql-server,xml,sql-server-2008,ado.net,xml-serialization,Sql Server,Xml,Sql Server 2008,Ado.net,Xml Serialization,我想将任意XML插入SQL Server。XML包含在XmlDocument对象中 我想插入的列可以是nvarchar,ntext,也可以是xml列(如果它能让您的生活更轻松,那么您可以选择它是哪种类型。实际上,它是xml列。) 原型 我问这个问题的原因是因为我试图找到正确的方法将XmlDocument转换为数据库可以使用的内容-确保编码正确: 我必须确保插入期间使用的编码与数据库所采用的编码匹配 我必须同步元素 我知道ntext、nvarchar或xml在SQL Server中存储为UTF
XmlDocument
对象中
我想插入的列可以是nvarchar
,ntext
,也可以是xml
列(如果它能让您的生活更轻松,那么您可以选择它是哪种类型。实际上,它是xml
列。)
原型
我问这个问题的原因是因为我试图找到正确的方法将XmlDocument
转换为数据库可以使用的内容-确保编码正确:
- 我必须确保插入期间使用的编码与数据库所采用的编码匹配
- 我必须同步
元素
ntext
、nvarchar
或xml
在SQL Server中存储为UTF-16
。因此,我必须确保将数据作为UTF-16提供给SQL Server。对于.NET中的String
s来说,这不是问题,因为它们是unicode UTF-16
第二个问题,同步编码属性,是一个更难解决的问题。我必须找出如何通过XmlDocument
对象找到声明元素:
<?xml version="1.0" encoding="windows-1252"?> (or whatever the encoding may be)
这会失败,因为我尝试运行的sql
是:
INSERT INTO LiveData (RawXML)
VALUES ('System.Xml.XmlDocument')
这是因为XmlDocument.ToString()
返回“System.Xml.XmlDocument
”。窥视一下实现,它会发现它实际上在调用:
this.GetType().ToString();
旁白:微软似乎特意阻止了你
将Xml作为字符串获取-
大概是因为它会导致bug
(但他们没有告诉我们什么是bug,为什么
它们是虫子,或者说是正确的方法
将XmlDocument
转换为
字符串
!)
另见
command.Parameters.Add(
new SqlParameter("@xml", SqlDbType.Xml)
{Value = new SqlXml(new XmlTextReader(xmlToSave.InnerXml
, XmlNodeType.Document, null)) })
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;
}
}
}
SQL应该如下所示:
String sql = "INSERT INTO "+tableName+" ("+columnName+") VALUES (@xml)";
由于第一个子节点始终是xml节点,因此可以使用以下语句替换编码
xmlToSave.FirstChild.InnerText = "version=\"1.0\" encoding=\"UTF-16\"";
总而言之,它看起来是这样的:
command.Parameters.Add(
new SqlParameter("@xml", SqlDbType.Xml)
{Value = new SqlXml(new XmlTextReader(xmlToSave.InnerXml
, XmlNodeType.Document, null)) })
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;
}
}
}
最简单的解决方案是使用文档的OuterXml属性。我在无法执行存储过程的情况下尝试解决问题时遇到了您的问题。OuterXml返回您希望从.Value或.ToString()获取的文本字符串
迟做总比不做好。。。我想你在找这样的东西:
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;
}
}
}
throw;
XmlNodeReader对象遍历XmlDocument(或任何其他XmlNode)并对其进行正确编码,SqlXml对象将其封装到适合与参数一起使用的SqlDbType中。这比使用字符串中介更安全、更高效。只是想添加一个与Jonathan Overholt的解决方案等效的SQLConnection:
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
}
在Visual studio 2017和2013中使用.net(版本4.6.2之前)测试正常,并与MS SQL Server 2008 R2、2012和2016进行对比
如果标识插入失败,您希望停止该过程,只需在transaction.Rollback()之后插入一行,如下所示:
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;
}
}
}
throw;
或者,您可以在任何情况下通过放置事务来停止该过程。Rollback();和扔;在条件(if)之外的行这个问题可能是相关的:我修改了SqlParameter值,它必须是sqlxml类型的值。我想你不是指
xmlToSave.ToString()
,因为它返回字符串“System.Xml.XmlDocument
”,它不是有效的Xml。当然,你是对的。据我记忆所及,一定是b。xmlToSave.ValueUps-使用示例重新设置;)它是xmlToSave.InnerXml var doc=new XmlDocument();文件加载(@“d:\temp\test.htm”);Console.Out.WriteLine(doc.InnerXml);还添加了xml编码的替换;)