Сохранение столбца DateTime в Cassandra Date - PullRequest
0 голосов
/ 09 мая 2018

Документация драйвера Cassandra .NET невероятно плохая, я пытаюсь собрать что-то функциональное, но я трачу столько времени, пытаясь изменить код из найденных мной документов Java.

Я пытаюсь записать данныена простую таблицу с помощью драйвера Cassandra.Таблица уже существует, и внутри есть дата.Я создал отображение и добавил несколько столбцов.Вот урезанная версия для демонстрации:

For<Profile>().TableName("profiles")
    .PartitionKey(p => p.IntegerId)
    .Column(p => p.IntegerId, cm => cm.WithName("profileid"))
    .Column(p => p.BirthDate, cm => cm.WithName("dateofbirth"))

Есть еще столбцы и таблицы, но это важная часть.

Затем сохранение выполняется с помощью простого универсального метода:

public async Task<bool> Add<T>(T item) where T : EntityBase, new()
{
    await _mapper.InsertIfNotExistsAsync(item);
}

Снова там больше кода, но соответствующие части здесь.Важно то, что я использую InsertIfNotExists и использую универсальный метод, который работает с базовой сущностью.

dateofbirth столбец в Cassandra имеет тип Date.Когда я запускаю метод Insert, я получаю исключение, что длина Date должна составлять 4 байта вместо 8 (я предполагаю, что мне нужно отрезать часть времени DateTime).

Я пытался использовать WithType для отображенияи создание TypeSerializer, подобного тому, что было описано на этом вопросе , но безуспешно.У кого-нибудь есть рабочий код, который сохраняет этот тип (и, возможно, другие типы) в Cassandra?

Вот код для кодека даты, который был адаптирован из Интернета, и как он использовался, он может быть (очень)неправильно:

public class DateCodec : TypeSerializer<DateTime>
{
    private static TypeSerializer<LocalDate> _innerSerializer;

    public DateCodec(TypeSerializer<LocalDate> serializer)
    {
        _innerSerializer = serializer;
        TypeInfo = new CustomColumnInfo("LocalDate");
    }

    public override IColumnInfo TypeInfo { get; }

    public override DateTime Deserialize(ushort protocolVersion, byte[] buffer, int offset, int length, IColumnInfo typeInfo)
    {
        var result = _innerSerializer.Deserialize(protocolVersion, buffer, offset, length, typeInfo);
        return new DateTime(result.Year, result.Month, result.Day);
    }

    public override ColumnTypeCode CqlType { get; }

    public override byte[] Serialize(ushort protocolVersion, DateTime value)
    {
        return _innerSerializer.Serialize(protocolVersion, new LocalDate(value.Year, value.Month, value.Day));
    }
}

Использование:

TypeSerializerDefinitions definitions = new TypeSerializerDefinitions();
definitions.Define(new DateCodec(TypeSerializer.PrimitiveLocalDateSerializer));

var cluster = Cluster.Builder()
    .AddContactPoints(...)
    .WithCredentials(...)
    .WithTypeSerializers(definitions)
    .Build();

1 Ответ

0 голосов
/ 10 мая 2018

Драйвер C # использует класс LocalDate для представления date от Cassandra, поэтому либо нужно изменить ваше объявление dateofbirth, чтобы использовать его, либо разработать соответствующий кодек.

Вы можете проверить документацию по представлению даты и времени для драйвера C #: https://docs.datastax.com/en/developer/csharp-driver/3.5/features/datatypes/datetime/

Обновление после обновления вопроса с примером кода:

Определить таблицу и вставить пример данных:

cqlsh> create table test.dt(id int primary key, d date);
cqlsh> insert into test.dt(id, d) values(1, '2018-05-17');
cqlsh> insert into test.dt(id, d) values(2, '2018-05-16');
cqlsh> insert into test.dt(id, d) values(3, '2018-05-15');

Для меня следующие конвертированные работы:

public class DateCodec : TypeSerializer<DateTime>
{
    private static readonly TypeSerializer<LocalDate> serializer = 
         TypeSerializer.PrimitiveLocalDateSerializer;

    public override ColumnTypeCode CqlType
    {
        get { return ColumnTypeCode.Date; }
    }

    public DateCodec() { }

    public override DateTime Deserialize(ushort protocolVersion, byte[] buffer, 
         int offset, int length, IColumnInfo typeInfo)
    {
        var result = serializer.Deserialize(protocolVersion, buffer,
                offset, length, typeInfo);
        return new DateTime(result.Year, result.Month, result.Day);
    }

    public override byte[] Serialize(ushort protocolVersion, DateTime value)
    {
        return serializer.Serialize(protocolVersion, 
            new LocalDate(value.Year, value.Month, value.Day));
    }
}

Основная программа:

TypeSerializerDefinitions definitions = new TypeSerializerDefinitions();
definitions.Define(new DateCodec());

var cluster = Cluster.Builder()
         .AddContactPoints("localhost")
         .WithTypeSerializers(definitions)
         .Build();
var session = cluster.Connect();
var rs = session.Execute("SELECT * FROM test.dt");
foreach (var row in rs)
{
    var id = row.GetValue<int>("id");
    var date = row.GetValue<DateTime>("d");
    Console.WriteLine("id=" + id + ", date=" + date);
}

var pq = session.Prepare("insert into test.dt(id, d) values(?, ?);");
var bound = pq.Bind(10, new DateTime(2018, 04, 01));
session.Execute(bound);

Дает в результате следующее:

id=1, date=5/17/18 12:00:00 AM
id=2, date=5/16/18 12:00:00 AM
id=3, date=5/15/18 12:00:00 AM

И проверка с cqlsh:

cqlsh> SELECT * from test.dt ;

 id | d
----+------------
 10 | 2018-04-01
  1 | 2018-05-17
  2 | 2018-05-16
  3 | 2018-05-15
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...