Reputation: 4916
I have the following c# class
public class Data
{
public string A {get;set;}
public string B {get;set;}
public string C {get;set;}
}
I create an instance of this in my code:
var d = new Data { A = "abc", B = string.Empty, C = null};
I need to convert this to XML and pass it to a sproc in SQL Server 2008.
I do this using:
var xml = new XElement("Data",
new XElement("A", d.A),
new XElement("B", d.B),
new XElement("C", d.C));
The resultant XML in the sproc is:
<Data>
<A>abc</A>
<B></B>
<C />
</Data>
So, there's a difference between an empty string an a null value.
Then in SQL, I'm using the following syntax to read the XML:
INSERT INTO #myTable
SELECT
nref.value('(A/text())[1]', 'uniqueidentifier') [A],
nref.value('(B/text())[1]', 'uniqueidentifier') [B],
nref.value('(C/text())[1]', 'uniqueidentifier') [C],
FROM @DataXml.nodes('/Data') AS R(nref);
But this is providing me with B and C both as NULL, where B should be empty string.
How can I adapt this to ensure that nulls remain as nulls and empty strings remain as empty strings?
Thanks
Upvotes: 2
Views: 2611
Reputation: 3145
XElement constructor may treat NULL and empty differently, but the XML spec considers < X /> and < X>< /X> to be identical. SQL server XQuery treats them identically as well.
If you want SQL server to distinguish between empty & null elements, you need to exclude the null element completely when you construct the XML in your C# code. For example, the below treats element B as empty & element C as NULL, since it's missing:
declare @x xml =
'<Data><A>abc</A><B></B></Data>'
SELECT
nref.value('(A/text())[1]', 'varchar') [A],
isnull(nref.value('(B/text())[1]', 'varchar'), case when nref.exist('./B') = 1 then '' end) [B],
isnull(nref.value('(C/text())[1]', 'varchar'), case when nref.exist('./C') = 1 then '' end) [C]
FROM @x.nodes('/Data') AS R(nref);
Upvotes: 2