オブジェクトをシリアル化して、SQL Server 2008xmlフィールドに保存しようとしています。また、オブジェクトを再水和する逆シリアル化コードもあります。オブジェクトをシリアル化してデータベースに保存することはできますが、「ルート要素がありません」という例外が発生します。
[XmlRoot("Patient")]
public class PatientXml
{
private AddressXml _address = null;
private EmergencyContactXml _emergencyContact = null;
private PersonalXml _personal = null;
[XmlElement]
public PersonalXml Personal
{
get { return _personal; }
set { _personal = value; }
}
[XmlElement]
public AddressXml Address
{
get { return _address; }
set { _address = value; }
}
[XmlElement]
public EmergencyContactXml EmergencyContact
{
get { return _emergencyContact; }
set { _emergencyContact = value; }
}
public PatientXml(){}
public PatientXml(Patient patient)
{
_address = new AddressXml(patient.Address);
_emergencyContact = new EmergencyContactXml(patient.EmergencyInfo);
_personal = new PersonalXml(patient);
}
}
public class PersonalXml
{
private string _firstName = string.Empty, _lastName = string.Empty, _dateOfBirth = string.Empty, _phone = string.Empty;
[XmlAttribute]
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
[XmlAttribute]
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
[XmlAttribute]
public string DateOfBirth
{
get { return _dateOfBirth; }
set { _dateOfBirth = value; }
}
[XmlAttribute]
public string Phone
{
get { return _phone; }
set { _phone = value; }
}
public PersonalXml(){}
public PersonalXml(Patient patient)
{
_firstName = patient.FirstName;
_lastName = patient.LastName;
_dateOfBirth = patient.DateOfBirth.ToShortDateString();
_phone = patient.Phone;
}
}
public class AddressXml
{
private string _address1 = string.Empty, _address2 = string.Empty, _city = string.Empty, _state = string.Empty, _Zip = string.Empty;
[XmlAttribute]
public string Address1
{
get { return _address1; }
set { _address1 = value; }
}
[XmlAttribute]
public string Address2
{
get { return _address2; }
set { _address2 = value; }
}
[XmlAttribute]
public string City
{
get { return _city; }
set { _city = value; }
}
[XmlAttribute]
public string State
{
get { return _state; }
set { _state = value; }
}
[XmlAttribute]
public string Zip
{
get { return _Zip; }
set { _Zip = value; }
}
public AddressXml(){}
public AddressXml(Address address)
{
_address1 = address.Address1;
_address2 = address.Address2;
_city = address.City;
_state = address.State;
_Zip = address.ZipCode;
}
}
public class EmergencyContactXml
{
private string _name = string.Empty, _phone = string.Empty, _relationship = string.Empty;
[XmlAttribute]
public string Name
{
get { return _name; }
set { _name = value; }
}
[XmlAttribute]
public string Phone
{
get { return _phone; }
set { _phone = value; }
}
[XmlAttribute]
public string Relationship
{
get { return _relationship; }
set { _relationship = value; }
}
public EmergencyContactXml(){}
public EmergencyContactXml(EmergencyContact contact)
{
_name = contact.ContactName;
_phone = contact.Phone;
_relationship = contact.Relationship;
}
}
シリアル化されたXml出力:
<Patient
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Personal FirstName="Test" LastName="User 1" DateOfBirth="3/13/1966" Phone="6304449866" />
<Address Address1="123 Some St" City="Bartlett" State="CT" Zip="60111" />
<EmergencyContact Name="Dr Chanduwarthana" Phone="6309769484" Relationship="Father" />
</Patient>
シリアル化と逆シリアル化のコード:
public static class XmlSerializer
{
public static string Serialize<T>(T item)
{
MemoryStream memStream = new MemoryStream();
using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
serializer.Serialize(textWriter, item);
memStream = textWriter.BaseStream as MemoryStream;
}
if (memStream != null)
return Encoding.Unicode.GetString(memStream.ToArray());
else
return null;
}
public static T Deserialize<T>(string xmlString)
{
if (string.IsNullOrWhiteSpace(xmlString))
return default(T);
using (MemoryStream memStream = new MemoryStream())
{
using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
{
memStream.Position = 0;
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
return (T)serializer.Deserialize(memStream);
}
}
}
}
デシリアライズコードでは、MemoryStreamとXmlTextWriterを作成していますが、デシリアライズする文字列を指定していません。
using (MemoryStream memStream = new MemoryStream())
{
using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
{
// Omitted
}
}
バイトをメモリストリームに渡し、XmlTextWriterを完全に廃止することができます。
using (MemoryStream memStream = new MemoryStream(Encoding.Unicode.GetBytes(xmlString)))
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
return (T)serializer.Deserialize(memStream);
}
XMLへのシリアル化を理解したようですので、私のアドバイスに従って、XMLを特殊なフィールドではなく文字列フィールド(varchar、nvarchar、text、ntext)に格納してください。
その小さな切り替えを行うと、準備が整います...それ以上の変更は必要ありません。
XMLフィールドは検証の対象であり、いくつかの頭痛の種があります。アプリケーションがそのフィールドのプロデューサーとコンシューマーのみである場合は、そのショートカットを使用することをお勧めします。 SQL2008(2005でも)は、xmlフィールドをコンパイルすることで節約できるリソースを補うのに十分な強度があります。
ただし、コードを少し最適化すると、必要以上に多くのコードを記述したように見えます。たとえば、プロパティのデータを保存するためにプライベートフィールドを作成する必要はなくなりました。次に例を示します。
public PersonalXml Personal
{
get { return _personal; }
set { _personal = value; }
}
あなたがそれを次のように書いた場合、うまくいくでしょう:
public PersonalXml Personal { get ; set ; }
あなたが切ることができたより多くの脂肪があります...
XMLヘッダーを追加する必要があると思います。
<?xml version="1.0" encoding="utf-8" ?>
シリアル化メソッドを変更して、これを追加するオプションのパラメーターを受け入れることができます。
public static string Serialize<T>(T item, bool includeHeader = false)
{
MemoryStream memStream = new MemoryStream();
using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
serializer.Serialize(textWriter, item);
memStream = textWriter.BaseStream as MemoryStream;
}
if (memStream != null)
if (includeHeader)
{
return @"<?xml version=""1.0"" encoding=""utf-8"" ?>" + Environment.NewLine + Encoding.Unicode.GetString(memStream.ToArray());
}
else
{
return Encoding.Unicode.GetString(memStream.ToArray());
}
else
return null;
}