0

我有一个需要读/写的 DynamoDB 表。我正在尝试使用 Kotlin 创建一个用于从 DynamoDB 读取和写入的模型。但我com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: MyModelDB[myMap]; could not unconvert attribute在跑步时不断遇到dynamoDBMapper.scanPage(...)。有时myMapMyListOfMaps相反,但我想这是通过迭代 Map 的键。

我的代码如下:

@DynamoDBTable(tableName = "") // Non-issue, I am assigning the table name in the DynamoDBMapper
data class MyModelDB(

    @DynamoDBHashKey(attributeName = "id")
    var id: String,

    @DynamoDBAttribute(attributeName = "myMap")
    var myMap: MyMap,

    @DynamoDBAttribute(attributeName = "MyListOfMapItems")
    var myListOfMapItems: List<MyMapItem>,
) {
    constructor() : this(id = "", myMap = MyMap(), myListOfMaps = mutableListOf())

    @DynamoDBDocument
    class MyMap {
        @get:DynamoDBAttribute(attributeName = "myMapAttr")
        var myMapAttr: MyMapAttr = MyMapAttr()

        @DynamoDBDocument
        class MyMapAttr {
            @get:DynamoDBAttribute(attributeName = "stringValue")
            var stringValue: String = ""
        }
    }

    @DynamoDBDocument
    class MyMapItem {
        @get:DynamoDBAttribute(attributeName = "myMapItemAttr")
        var myMapItemAttr: String = ""
    }
}

我正在使用该com.amazonaws:aws-java-sdk-dynamodb:1.11.500软件包,并且我dynamoDBMapper的初始化是DynamoDBMapperConfig.Builder().build()(以及其他一些配置)。

我的问题是我做错了什么,为什么?我还看到一些 Java 实现使用DynamoDBTypeConverter. 它更好吗,我应该改用它吗?

任何例子将不胜感激!

4

2 回答 2

1

这里有一些评论。首先,您没有使用适用于 Kotlin 的 AWS 开发工具包。您正在使用另一个 SDK 并简单地编写 Kotlin 代码。使用此 SDK,您无法获得 Kotlin 的全部优势,例如对协程的支持。

适用于 Kotlin的AWS 开发工具包(确实提供对 Kotlin 功能的完全支持)本周刚刚作为 DEV 预览版发布。请参阅开发指南:

为 Kotlin 设置 AWS 开发工具包

但是,此 SDK 目前不支持此映射。要使用适用于 Kotlin 的 AWS开发工具包将项目放入 Amazon DynamoDB 表中,您需要使用:

mutableMapOf<String, AttributeValue>

完整的例子在这里

要将 Java 对象映射到 DynamoDB 表,您应该考虑使用AWS SDK for Java V2 中的DynamoDbEnhancedClient请参阅AWS SDK for Java V2 开发人员指南中的此主题:

映射 DynamoDB 表中的项目

您可以在AWS Github 存储库中找到使用增强型客户端的其他示例。

于 2021-12-03T13:42:46.970 回答
0

好的,由于一些帮助,我最终得到了这个工作。在得到更好的理解后,我稍微编辑了这个问题。以下是我的数据类最终的结果。对于 Java 用户,Kotlin 编译为 Java,所以如果你能弄清楚转换是如何工作的,那么你的使用思路也应该是一样的。

data class MyModelDB(

    @DynamoDBHashKey(attributeName = "id")
    var id: String = "",

    @DynamoDBAttribute(attributeName = "myMap")
    @DynamoDBTypeConverted(converter = MapConverter::class)
    var myMap: Map<String, AttributeValue> = mutableMapOf(),

    @DynamoDBAttribute(attributeName = "myList")
    @DynamoDBTypeConverted(converter = ListConverter::class)
    var myList: List<AttributeItem> = mutableListOf(),
) {
    constructor() : this(id = "", myMap = MyMap(), myList = mutableListOf())
}

class MapConverter : DynamoDBTypeConverter<AttributeValue, Map<String,AttributeValue>> {
    override fun convert(map: Map<String,AttributeValue>>): AttributeValue {
        return AttributeValue().withM(map)
    }

    override fun unconvert(itemMap: AttributeValue?): Map<String,AttributeValue>>? {
        return itemMap?.m
    }

}

class ListConverter : DynamoDBTypeConverter<AttributeValue, List<AttributeValue>> {
    override fun convert(list: List<AttributeValue>): AttributeValue {
        return AttributeValue().withL(list)
    }

    override fun unconvert(itemList: AttributeValue?): List<AttributeValue>? {
        return itemList?.l
    }

}

这至少可以让我使用我的自定义转换器将我的数据从 DynamoDB 中取出。我将继续定义一个单独的数据容器类以在我自己的应用程序中使用,并且我创建了一个方法来在这两个数据对象之间进行序列化和反序列化。这更像是您希望如何处理数据的偏好,但这对我来说就是这样。

// For reading and writing to DynamoDB
class MyModelDB {
    ...
    fun toMyModel(): MyModel {
        ...
    }
}

// For use in my application
class MyModel {
    var id: String = ""
    var myMap: CustomObject = CustomObject()
    var myList<CustomObject2> = mutableListOf()

    fun toMyModelDB():MyModelDB {
        ...
    }
}

最后,我们来实现这2个toMyModel.*()方法。让我们从输入开始,这就是我的列的样子:

我的地图

{
    "key1": {
        "M": {
            "subKey1": {
                "S": "some"
            },
            "subKey2": {
                "S": "string"
            }
        }
    },
    "key2": {
        "M": {
            "subKey1": {
                "S": "other"
            },
            "subKey2": {
                "S": "string"
            }
        }
    }
}

我的清单

[
    {
        "M": {
            "key1": {
                "S": "some"
            },
            "key2": {
                "S": "string"
            }
        }
    },
    {
        "M": {
            "key1": {
                "S": "some string"
            },
            "key3": {
                "M": {
                    "key4": {
                        "S": "some string"
                    }
                }
            }
        }
    }
]

然后诀窍是用来com.amazonaws.services.dynamodbv2.model.AttributeValue转换 JSON 中的每个字段。因此,如果我想访问subKey2inkey1字段的值myMap,我会这样做:

myModelDB.myMap["key1"]
        ?.m // Null check and get the value of key1, a map
        ?.get("subKey2") // Get the AttributeValue associated with the "subKey2" key
        ?.s // Get the value of "subKey2" as a String

这同样适用于myList

myModelDB.myList.foreach {
        it?.m // Null check and get the map at the current index
        ?.get("key1") // Get the AttributeValue associated with the "key1"
        ...
}

编辑:怀疑这将是一个很大的问题,但我也将我的 DynamoDB 依赖项更新为com.amazonaws:aws-java-sdk-dynamodb:1.12.126

于 2021-12-13T08:15:17.210 回答