【问题标题】:Servicestack ORMLite - Using XML fields in PostgreSQLServicestack ORMLite - 在 PostgreSQL 中使用 XML 字段
【发布时间】:2019-10-15 21:23:02
【问题描述】:

我有一个 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 的标准插入语句?

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

【问题讨论】:

    标签: postgresql ormlite-servicestack


    【解决方案1】:

    您可以使用 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。

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

    【讨论】:

    • 令人难以置信的是,您不仅可以找到解决方案,而且可以在如此短的时间内将其纳入拉取请求。谢谢,这将涵盖我需要的一切。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-28
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    相关资源
    最近更新 更多