如何将实体列映射到 Spring Data JDBC 中的 json Key

问题描述

这是我的实体

@Table("amazon_rds_inventory")
public class AmazonDBInstanceDataSelect {
    @Id
    @Column("id")
    private long id;

    @Column("inventory_Metadata")
    private String inventoryMetadata;

    @Column("aws_identifier")
    private String awsIdentifier;

    @Column("host")
    private String host;

    @Column("region")
    private String region;

    @Column("type")
    private AmazonInventoryType amazonInventoryType;

    @Column("created_by")
    private String user;

    @Column("created_on")
    private Timestamp createdOn;

    @Column("cloned")
    private boolean cloned;

    @Column("inventory_Metadata->>'$.dbclusterIdentifier' as clusterIdentifier")
    private String clusterIdentifier;

    @Column("deleted")
    private boolean deleted;

}

my table field

“inventory_Metadata”列的json数据

{
"port": 27017,"engine": "docdb","status": "available","multiAZ": false,"tagList": [],"capacity": null,"endpoint": "nimesa-docdb-cluster-01.cluster-cjzyjmw4obtv.us-east-1.docdb.amazonaws.com","kmsKeyId": "arn:aws:kms:us-east-1:220709770714:key/293f9b17-43fc-4946-92d6-cfcb9965a8cd","engineMode": "provisioned","cloneGroupId": null,"databaseName": null,"dbclusterarn": "arn:aws:rds:us-east-1:220709770714:cluster:nimesa-docdb-cluster-01","hostedZoneId": "ZNKXH85TT8WVW","dbsubnetGroup": "custom-subnetgroupwith-custom","engineVersion": "4.0.0","masterUsername": "nimesa","readerEndpoint": "nimesa-docdb-cluster-01.cluster-ro-cjzyjmw4obtv.us-east-1.docdb.amazonaws.com","associatedRoles": [],"backtrackWindow": null,"customEndpoints": [],"percentProgress": null,"allocatedStorage": 1,"characterSetName": null,"dbclusterMembers": [
    {
        "clusterWriter": true,"promotionTier": 1,"isClusterWriter": true,"dbinstanceIdentifier": "nimesa-docdb-01","dbclusterParameterGroupStatus": "in-sync"
    }
],"storageEncrypted": true,"availabilityZones": [
    "us-east-1f","us-east-1b","us-east-1a"
],"clusterCreateTime": 1615532359067,"crossAccountClone": false,"domainMemberships": [],"vpcSecurityGroups": [
    {
        "status": "active","vpcSecurityGroupId": "sg-05c8ed6d9836007fd"
    }
],"activityStreamMode": null,"copyTagsToSnapshot": false,"deletionProtection": false,"dbClusterResourceId": "cluster-6OQQJU32K2ZZE2GSTHP2DHNGZM","dbclusterIdentifier": "nimesa-docdb-cluster-01","httpEndpointEnabled": false,"activityStreamStatus": "stopped","latestRestorableTime": 1620666452774,"backupRetentionPeriod": 1,"earliestBacktrackTime": null,"pendingModifiedValues": null,"preferredBackupWindow": "00:00-00:30","activityStreamKmsKeyId": null,"earliestRestorableTime": 1620666452774,"readReplicaIdentifiers": [],"dbclusterParameterGroup": "default.docdb4.0","scalingConfigurationInfo": null,"preferredMaintenanceWindow": "wed:07:48-wed:08:18","globalWriteForwardingStatus": null,"replicationSourceIdentifier": null,"enabledCloudwatchLogsExports": [],"backtrackConsumedChangeRecords": null,"globalWriteForwardingRequested": null,"activityStreamKinesisstreamName": null,"dbclusterOptionGroupMemberships": [],"iamdatabaseAuthenticationEnabled": false

}

我得到的错误:- java.sql.sqlSyntaxErrorException: 未知列 'amazon_rds_inventory.inventory_Metadata->>'$.dbclusterIdentifier' as clusterIdentifier' in 'field list'

我想获取 json 中 dbclusterIdentifier 键的值并将其映射到我的实体

解决方法

根据具体目标,您有多种选择。

让我们从为什么当前的方法行不通开始。

  1. @Column 指定一列,而不是任意表达式。正如您所指出的,将其设置为表达式只会产生一个非常奇怪的列名。
  2. 即使它可以处理表达式,它也不仅需要一个表达式来提取值,还需要一个用于写回值的表达式。
  3. 该字段仅包含文档的一部分。如果可行,写回该值会将原始 JSON 文档替换为仅包含该值的文档。

让我们看看几个解决方案:

  1. 在您当前的设置中,您已经将完整的 JSON 文档加载为 inventoryMetadata。因此,我建议在加载后对实体进行后期处理。在您的应用程序上下文中注册一个 AfterLoadCallback,它将所需的值从 inventoryMetadata 提取到 clusterIdentifier

  2. 如果您真的想以结构化方式访问 JSON 文档,您可以使用自定义类型,例如 InventoryMetadata 并注册转换器以将其转换为 String 并返回,如果我记得正确应该适用于 SQL 标准,所以希望它适用于 MySQL。

  3. 如果您想将 JSON 处理排除在 Java 代码之外,您可以在数据库中有一个数据库视图并在那里进行任何提取/操作。您可以将您的实体映射到该视图。如果视图是可更新的,您甚至可以使用 if 来写回数据。

  4. 您描述的使用专用 @Query 的解决方案是另一种选择,当您只想读取数据时,它可以正常工作。