Использование joda DateTime Range Key с моделью персистентности объектов AWS DynamoDB
У меня есть таблица DynamodB с отметкой времени ("creationDate") в качестве диапазона. Модель использует йоду DateTime
сделать его простым в использовании (совместимость с остальным кодом). Чтобы можно было выполнять запросы между этими диапазонами, я использовал числовой тип для атрибута в таблице и планировал сохранить его как метку времени Java (миллисекунды с начала эпохи). Затем я добавил маршаллер для преобразования joda DateTime в String, представляющий long и наоборот.
Структура таблицы (создание):
void CreateTable()
{
CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(LinkManager.TABLE_NAME);
ProvisionedThroughput pt = new ProvisionedThroughput()
.withReadCapacityUnits(LinkManager.READ_CAPACITY_UNITS)
.withWriteCapacityUnits(LinkManager.WRITE_CAPACITY_UNITS);
createTableRequest.setProvisionedThroughput(pt);
ArrayList<AttributeDefinition> ad = new ArrayList<AttributeDefinition>();
ad.add(new AttributeDefinition().withAttributeName("creationDate").withAttributeType(ScalarAttributeType.N));
ad.add(new AttributeDefinition().withAttributeName("contentHash").withAttributeType(ScalarAttributeType.S));
createTableRequest.setAttributeDefinitions(ad);
ArrayList<KeySchemaElement> ks = new ArrayList<KeySchemaElement>();
ks.add(new KeySchemaElement().withAttributeName("contentHash").withKeyType(KeyType.HASH));
ks.add(new KeySchemaElement().withAttributeName("creationDate").withKeyType(KeyType.RANGE));
createTableRequest.setKeySchema(ks);
this.kernel.DDB.createTable(createTableRequest);
}
Модель:
@DynamoDBTable(tableName="Link")
public class Link {
private String ContentHash;
private DateTime CreationDate;
@DynamoDBHashKey(attributeName = "contentHash")
public String getContentHash() {
return ContentHash;
}
public void setContentHash(String contentHash) {
ContentHash = contentHash;
}
@DynamoDBRangeKey(attributeName = "creationDate")
@DynamoDBMarshalling(marshallerClass = DateTimeMarshaller.class)
public DateTime getCreationDate() {
return CreationDate;
}
public void setCreationDate(DateTime creationDate) {
CreationDate = creationDate;
}
}
Маршаллер:
public class DateTimeMarshaller extends JsonMarshaller<DateTime>
{
public String marshall(DateTime dt)
{
return String.valueOf(dt.getMillis());
}
public DateTime unmarshall(String dt)
{
long ldt = Long.parseLong(dt);
return new DateTime(ldt);
}
}
Я получаю следующую ошибку:
Exception in thread "main" com.amazonaws.AmazonServiceException: Type of specified attribute inconsistent with type in table (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 8aabb703-cb44-4e93-ab47-c527a5aa7d52)
Я предполагаю, что это потому, что маршаллер возвращает строку, а DynamoDB хочет числовой тип, так как тип атрибута - N. Я не знаю, что люди делают в этом случае, я искал решение, но не смог его найти. Я проверял это только на локальном экземпляре DynamodB, что, по-моему, не имеет никакого значения (проверка не пройдена, запрос не выполнен).
Очевидный обходной путь - использование длинного типа для дат в модели и добавление специальных методов получения и установки для работы с DateTime. Тем не менее, есть ли более чистый путь? Я уверен, что я не единственный, кто использует диапазон DatTime в модели.
1 ответ
Что бы я сделал, это заново создаю таблицу с ключом Range в качестве самой String. Даже если он будет заполнен длинными числами, его тип: S обеспечит совместимость с Marshaller.