LINQ to SQL 中 Xml (XElement) 字段的常见问题

cite=LINQ to SQL FAQ – XML columns in SQL

LINQ to SQL 目前不支持包含 XElement 查询的 Expression 对象

However, LINQ to SQL does not appear to support ANY translations of XML queries on XElement to SQL – this mans that the following statement :

will fail at runtime as the LINQ-to-SQL parser is unable to translate on our XML data column XmlCol query into an Xpath.

LINQ to SQL 目前不支持由 XElement 内部变化引起的记录更新

A LINQ to SQL xml datatype column is represented as an XElement. If you modify this be careful as LINQ to SQL will not spot internal changes to XElement and save them to the database.

For example:

will not alter the instance XElement and so will not change the Table.XMLdata entry. The workaround for this is to write it back as a new element:

 

XmlSerializer 大法好

请原谅我之前的愚昧无知。我已经决定完全分离对象模型和对象的逻辑行为了。

引用使用 Id 保存,即类中不再出现对其他类的直接引用,而仅仅保存 Id。这样在序列化的时候就可以直接保存了。

XmlSerializer 是线程安全的。
XmlSerializer 是线程安全的。

然而我发现处理 Nullable 类型还是一个很麻烦的问题……
c# – Is there any way for my class to support serialisation as an XML attribute? – Stack Overflow

所以我要自己造轮子!

好吧……我决定自己实现 XmlSerializer 了

重新造轮子 TT

ref = CXuesong/XSerializer/

欢迎围观 TT

最近一直在考虑以下问题:

在使用 XmlSerializer 以精确控制 XML 格式的同时

  1. 如何序列化 Nullable<T> 格式的数据,并将其保存为 XML 属性(而非元素)?
  2. 如何序列化对象的引用,使其不会以多个副本的形式保存?
  3. 在实现上面这两点(尤其是第一点)的时候,不会引入其他的公共辅助属性。
    (例如对于第一点,可以通过一个辅助属性,实现 Nullable<T>string 之间的转换,而 string 是可以保存为 XML 属性的。)

其中,第二个问题似乎可以使用 DataContractSeriallizer 来解决。然而 DataContractSeriallizer 会在生成 XML 时自行为对象确定 Id,并使用 z:Idz:Ref 来表示 Id 和 Id 引用。正如在前几篇文章中提到的那样,DataContractSeriallizer 对 XML 结构的控制自由度是十分有限的。

那么,如何才能圆满地解决这些问题呢?

我觉得,可以自己造轮子了。

 

在 XmlSerializer 与 DataContractSerializer 之间抉择

通常来说,当你想更加精确地控制生成的 XML 时,可以使用 XmlSerializer。如果你对生成的 XML 格式并不在意(例如所有的属性/字段均会以元素的形式保存),同时想保留对象的所有信息(包括私有属性/字段),则可以使用 DataContractSerializer继续阅读在 XmlSerializer 与 DataContractSerializer 之间抉择

XmlSerializer 测试 2

集合

运行结果为 True 。实际上,如果把 MyList 换成只读属性,只要其值非 null / Nothing,则程序仍可以正常运行。

也就是说,反序列化过程复用了已有的集合实例。 继续阅读XmlSerializer 测试 2

快对字体无奈了

好吧…… fonts.lug.ustc.edu.cn 貌似挂掉了。现在已经打算在本站嵌入字体了。

与此同时,发现 Useso take over Google 的作者已经开始着手修改源码了。以下是 1.6.1 版本的代码片段:

然后就发现了 极客族公共加速服务 ……

p.s.

我觉得 Useso take over Google 可以改名叫 “Geeks” take over Google 了 XD

XmlSerializer 测试

测试源代码如下,使用 VS2013 编写。

运行结果如下

可以看出,

  1. XmlArrayItem(Attribute)XmlElement 等相关特性中指定 IsNullable = true 可以使得当前为 null / Nothing 的元素在序列化时产生一个包含 xsi:nil="true" 特性的 XML 元素。
  2. 在特性中指定元素的命名空间时,应当指定命名空间的 URI,尽管可以稍后在 XmlSerializerNamespaces 中为这些 URI 指定对应的命名空间前缀。
  3. 需要序列化派生类时,总是 需要通过 XmlInclude 特性,或者通过 XmlSerializer 的构造函数显式声明序列化过程中可能用到的派生类。
  4.  数组的序列化:可以通过 XmlArrayItem 特性声明数组中可能包含的派生类类型。这些类型在序列化时会使用与之对应的元素名。如果存在未在 XmlArrayItem 中声明的派生类,而其基类在 XmlArrayItem 中声明过,则会使用基类对应的元素名,外加 xsi:type 特性声明实际派生类的类型。(关于这一点,可以参阅另一篇文章:MSDN中“(使用 XmlArrayItemAttribute 限定)序列化派生类”一节中的示例可能与实际有出入
  5. 我该滚去修改以前的代码了。

MSDN中“(使用 XmlArrayItemAttribute 限定)序列化派生类”一节中的示例可能与实际有出入

cite=https://msdn.microsoft.com/ZH-CN/library/vstudio/2baksw0z.aspx

XmlArrayItemAttribute 的另一种用法是,允许序列化派生类。 例如,可将派生自 Employee 的另一个名为 Manager 的类添加至上一示例中。 如果没有应用 XmlArrayItemAttribute,代码将在运行时失败,原因是无法识别派生类类型。 若要解决这个问题,每次为每个可接受类型(基类和派生类)设置 Type 属性时,需要应用该特性两次。

序列化实例可能如下所示。

然而实际情况不一样…… 继续阅读MSDN中“(使用 XmlArrayItemAttribute 限定)序列化派生类”一节中的示例可能与实际有出入