Servicestack ORMLite - 在 PostgreSQL 中使用 XML 字段

Servicestack ORMLite - Using XML fields in PostgreSQL

我有一个 Web 应用程序正在扩展以包含 PostgreSQL 作为数据库选项。对于现有的 MSSQL 实现,我们使用一个 XML 列来保存一个临时对象作为我们 POCO class.

的一部分
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: column "xmlvalue" is of type xml but expression is of type text

因此,我需要将该字符串转换为 xml 类型,而不是在 poco 模型中使用字符串并作为字符串插入。

有没有办法通过用属性标记字段或以其他方式将其标记为 xml 来覆盖 postgres 的标准插入语句?

我的另一个选择是简单地将列更改为文本,但这确实使查询列几乎不可能。

您可以使用 OrmLite Type Converters 自定义处理不同 .NET 类型的方式,但是您无法自定义 string,因为这会影响所有 string 字段。

相反,我刚刚在 this commit 中的 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 安装需要 configured --with-libxml to use the XML data type

now available on MyGet.

的 v5.7.1+ 开始提供 XmlValue 支持的更改