CompanyMarch 23, 2015

C# Driver for Cassandra 2.5.1 Released

C# Driver for Cassandra 2.5.1 Released

The new version of the C# Driver for Apache Cassandra is now available with support for manual paging and a friendlier routing API. On the Mapper and Linq components, it adds support for lightweight transactions.

Manual paging

When performing SELECT queries with large result sets, the driver automatically fetches a limited amount of rows by default retrieving the rows block by block as you iterate through the RowSet, to avoid having large amount of rows in memory.

Now it is possible to retrieve the next page based on the previous state, enabling you to store it and use it to fetch the following page in the future. This is useful for common scenarios like web pagers.

 

//prepare your queries once, as always
var ps = session.Prepare("SELECT * from tbl1 WHERE key = ?");
// Disable automatic paging.
var statement = ps
   .Bind(key)
   .SetAutoPage(false)
   .SetPageSize(pageSize);
var rs = session.Execute(statement);
// Store the paging state
var pagingState = rs.PagingState;

// Later in time ...
// Retrieve the following page of results.
var statement2 = ps
   .Bind(key)
   .SetAutoPage(false)
   .SetPagingState(pagingState)
var rs2 = Session.Execute(statement2);

The PagingState property of the RowSet is not encrypted and can be used to inject values to retrieve other partitions, so be careful not to expose it to the end user.

If you want to manually page using the Linq or the Mapper, you can use Linq's ExecutePaged() method, Mapper's FetchPage(), or their async counterparts.

Routing queries

When using the TokenAwarePolicy load balancing policy, the driver uses the RoutingKey to determine which nodes is used as coordinator for a given statement. Due to the endianness difference between .NET / Mono (based on target CPU architecture) and the Cassandra protocol, it used to be difficult to specify a routing key.

Now, that we've made it easier to deal with routing keys, lets look at some basic examples with the different type of statements.

Prepared statements

When using prepared statements, the driver will determine which of the query parameters compose the partition key based on the prepared statement metadata and it will do all the routing for you. There is an special case when using named parameters where this won't be the case, check the documentation for more information.

Batch statements

If you want to choose which partition to target when using BatchStatement, you must specify the values that compose the partition key.

//Consider a single uuid partition key
var partitionKey = Guid.NewGuid();
var batch = new Batch();
// ... Add statements to the query
batch.SetRoutingValues(partitionKey);
session.Execute(batch);

Simple statements

If you plan to execute your query more than once, you should use prepared statements instead of SimpleStatement. But if for some reason you want to define the routing key for a SimpleStatement you can now use the SetRoutingValues()

//Consider a partition key composed by a uuid and a string
var id = Guid.NewGuid();
var groupName = "A";
var query = new SimpleStatement(cql, id, groupName, value);
// Specify the values that compose the partition key
query.SetRoutingValues(id, groupName);
session.Execute(query);

Lightweight transactions support on Linq and the Mapper

When using Lightweight transactions (LWT), it is generally required to check the result of the operation to see if the operation was applied and if not, check the field values that didn't match the condition. Now, it is possible to do that with Linq and the Mapper.

LWT with Linq

//Update the password only if a temporary token matches
var info = users
  .Where(b => m.User == "User1")
  .Select(m => new User { Password = definitivePassword, Token = null })
  .UpdateIf(m => m.Token == token)
  .Execute();
if (!info.Applied)
{
  //It was not applied, you can check the existing value
  var userToken = info.Existing.Token;
}

LWT with the Mapper

var info = mapper.InsertIfNotExists(user);
if (!info.Applied)
{
  //It was not inserted, there was an existing user with the same keys
  //You can check the existing user
  User existingUser = info.Existing;
}

Wrapping Up

Version 2.5.1 of the C# driver is now available on Nuget, you can check all the tickets included in this release on Jira. Thanks to all who provided contributions and bug reports. The continued involvement of the community is appreciated, review or contribute source code on GitHub and join the project mailing list.

Share

One-Stop Data API for Production GenAI

Astra DB gives developers a complete data API and out-of-the-box integrations that make it easier to build production RAG apps with high relevancy and low latency.