postgresql - Servicestack ORMLite - 在 PostgreSQL 中使用 XML 字段

标签 postgresql ormlite-servicestack

我有一个 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: 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 的支持。通过使用仅包装 XML 字符串的包装器 XmlValue 类型:

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 .

此更改对 XmlValue 的支持可从 v5.7.1+ 获得,即 now available on MyGet .

关于postgresql - Servicestack ORMLite - 在 PostgreSQL 中使用 XML 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58402824/

相关文章:

ormlite-servicestack - 使用 ormlite 服务堆栈进行热切加载

python - 使用 Python 转储 PostgreSQL 数据库模式

php - 如何在 Linux 上的 XAMPP 中启用 PostgreSQL

sql - Django 查询 Postgres 返回错误列

sql - 如何按两列聚合多个点并从中创建一个 LineString/MultiLineString

c# - 在 .Net Core 中的 ServiceStack.OrmLite 上使用 SqlGeography

Servicestack ORMLite 查询多个

java - 保存在 Web 应用程序中

servicestack - 从 SqlExpression<T> 获取 tableDef

c# - 如何使用 OrmLite 固定大小而不是 null varchar?