Cassandra .NET driver documentation is unbelievably poor, I'm trying to scrap together something functional but I waste so much time trying to change code from Java documents that I found.
I am trying to write data to a simple table using Cassandra driver. The table already exists and there's date inside. I have created a mapping and added some columns. Here's a cut-off version to demonstrate:
For<Profile>().TableName("profiles")
.PartitionKey(p => p.IntegerId)
.Column(p => p.IntegerId, cm => cm.WithName("profileid"))
.Column(p => p.BirthDate, cm => cm.WithName("dateofbirth"))
There are more columns and tables but that this the important part.
Then saving is done from a simple generic method:
public async Task<bool> Add<T>(T item) where T : EntityBase, new()
{
await _mapper.InsertIfNotExistsAsync(item);
}
Again there's more code there, but the relevant parts are here. What's important is that I'm using InsertIfNotExists and using generic method that works with a base entity.
dateofbirth
column in Cassandra is of type Date.
When I run the Insert method I get exception that the length of Date should be 4 bytes instead of 8 (I assume I need to cut off the time part of the DateTime).
I tried using WithType on the mapping and creating a TypeSerializer similar to what was described at this question, but had no luck. Anyone has a working code that saves this type (and possibly other types) to Cassandra?
Here's the code for the date codec that was adapted from the internet, and how it was used, it might be (very) wrong:
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));
}
}
Usage:
TypeSerializerDefinitions definitions = new TypeSerializerDefinitions();
definitions.Define(new DateCodec(TypeSerializer.PrimitiveLocalDateSerializer));
var cluster = Cluster.Builder()
.AddContactPoints(...)
.WithCredentials(...)
.WithTypeSerializers(definitions)
.Build();
In Cassandra 3.4 and later, timestamps are displayed in cqlsh in sub-second precision by default, as shown below. Applications reading a timestamp may use the sub-second portion of the timestamp, as Cassandra stored millisecond-precision timestamps in all versions.
Inserting the current timestamp Use functions to insert the current date into date or timestamp fields as follows: Current date and time into timestamp field: toTimestamp(now()) sets the timestamp to the current time of the coordinator.
C# driver uses LocalDate
class to represent date
from Cassandra, so either need to change your declaration of dateofbirth
to use it, or develop corresponding codec.
You can check the documentation on date and time representation for the C# driver: https://docs.datastax.com/en/developer/csharp-driver/3.5/features/datatypes/datetime/
Update after update of the question with code sample:
Define table & insert sample data:
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');
Following converted works for me:
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));
}
}
Main program:
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);
Gives as result following:
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
And checking from cqlsh
:
cqlsh> SELECT * from test.dt ;
id | d
----+------------
10 | 2018-04-01
1 | 2018-05-17
2 | 2018-05-16
3 | 2018-05-15
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With