postgresql - Servicestack ORMLite - 在 PostgreSQL 中使用 XML 字段
问题描述
我有一个 Web 应用程序正在扩展以包含 PostgreSQL 作为数据库选项。对于现有的 MSSQL 实现,我们使用 XML 列将临时对象保存为 POCO 类的一部分。
public class POCO
{
[PrimaryKey]
public int POCOId { get; set; }
public string StringValue { get; set; }
public string XMLValue{ get; set; }
}
在 MSSQL 中,我们可以插入如下值,其中 GenerateXML 生成转换为字符串的有效 xml:
var poco= new POCO
{
StringValue ="My string here!"
XMLValue= GenerateXML().ToString()
};
using (var context= new OrmContext())
context.Connection.Insert(poco);
MSSQL 接受 XML 字符串并将其正确插入数据库。但是 postgres 要求将 xml 显式插入为 xml:
42804:列“xmlvalue”的类型为 xml,但表达式的类型为文本
因此,我需要将该字符串转换为 xml 类型,而不是在 poco 模型中使用字符串并作为字符串插入。
有没有办法通过使用属性标记字段或将其标记为 xml 来覆盖 postgres 的标准插入语句?
我的另一个选择是简单地将列更改为文本,但这确实使查询列几乎不可能。
解决方案
您可以使用OrmLite 类型转换器自定义如何处理不同的 .NET 类型,但是您将无法自定义string
,因为这会影响所有string
字段。
相反,我刚刚在此提交中添加了对 PostgreSQL 中 Xml 的支持,方法是使用XmlValue
仅包装 XML 字符串的包装器类型:
public struct XmlValue
{
public string Xml { get; }
public XmlValue(string xml) => Xml = xml;
public override string ToString() => Xml;
public bool Equals(XmlValue other) => Xml == other.Xml;
public override bool Equals(object obj) => obj is XmlValue other && Equals(other);
public override int GetHashCode() => Xml != null ? Xml.GetHashCode() : 0;
public static implicit operator XmlValue(string expandedName) =>
expandedName != null ? new XmlValue(expandedName) : null;
}
所以我们可以自定义它的处理方式PostgreSqlXmlConverter
:
public class PostgreSqlXmlConverter : PostgreSqlStringConverter
{
public override string ColumnDefinition => "XML";
public override void InitDbParam(IDbDataParameter p, Type fieldType) => p.DbType = DbType.Xml;
public override object ToDbValue(Type fieldType, object value) => value?.ToString();
public override string ToQuotedString(Type fieldType, object value) =>
base.ToQuotedString(fieldType, value.ToString());
}
您可以通过以下方式注册PostgreSqlDialect.Provider
:
PostgreSqlDialect.Provider.RegisterConverter<XmlValue>(new PostgreSqlXmlConverter());
您现在可以使用XmlValue
数据类型创建表和插入行,例如:
public class XmlTest
{
public int Id { get; set; }
public XmlValue Xml { get; set; }
}
您可以使用 PostgreSQL XML 函数创建、插入和查询:
using (var db = dbFactory.OpenDbConnection())
{
db.DropAndCreateTable<XmlTest>();
db.Insert(new XmlTest { Id = 1, Xml = @"<attendee>
<bio>
<name>John Doe</name>
<birthYear>1986</birthYear>
</bio>
<languages>
<lang level=""5"">php</lang>
<lang level=""4"">python</lang>
<lang level=""2"">java</lang>
</languages>
</attendee>" });
db.Insert(new XmlTest { Id = 2, Xml = @"<attendee>
<bio>
<name>Tom Smith</name>
<birthYear>1978</birthYear>
</bio>
<languages>
<lang level=""5"">python</lang>
<lang level=""3"">java</lang>
<lang level=""1"">ruby</lang>
</languages>
</attendee>" });
var results = db.Column<string>(@"SELECT
(xpath('//bio/name/text()', Xml)::text[])[1]
FROM xml_test
WHERE cast(xpath('//bio[birthYear>1980]', Xml) as text[]) != '{}'");
results[0] //= John Doe
}
请注意,您的 PostgreSQL 安装需要配置 --with-libxml 以使用 XML 数据类型。
XmlValue
从 v5.7.1+ 开始提供此支持更改,现在可在 MyGet 上使用。
推荐阅读
- python - Flask: 'NoneType' object has no attribute 'drivername' when querying a table from Python terminal
- ios - React Native 到 Swift 桥 - 传递参数和回调
- android - Some drawables doesn't show up
- javascript - Variables changing in Loop
- excel - VBA Script to Create PDF from Excel Goes to Printer and Doesn't Export File
- discord.js - 如何让我的不和谐机器人只在聊天中工作?
- javascript - 如何修复 Angular *ngFor DOM 节点泄漏
- javascript - 反应:我如何摆脱这个最大更新深度超出错误
- python - Python PhantomJS 无法获取所有 html
- ansible - 如何同步和备份文件