Использование 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.

Другие вопросы по тегам