-
Notifications
You must be signed in to change notification settings - Fork 1
Cassandra Object Mapper
The Cassandra Object Mapper is a framework that allows easy mapping of CLR objects to and from Cassandra rows/records. Cassandra terminology can take a lot of getting used to, and this article may not always get it right (it’s a wiki – fix it). The general idea is that we’d like to create a plain old .Net class, adorn it with some attributes, and then be able to load and save it from Cassandra, including lazy loading “related” Cassandra objects. Our not-so-hypothetical example will be a simple Customer object. We’ve named the object CCustomer, because we also use a relational store for things which require transactional consistency, and that uses BLToolkit to generate entities from the database, so it gets to keep the “Customer” class name. Sorry Cassandra, maybe someday you can has Customer.
So, our declaration looks like this:
[CassandraEntity("MyKeyspace", "Customer")]
public class CCustomer : CassandraEntity<int>
{
/// <summary>
/// Needs to be here for simpler generic constraints, perhaps there's a better declaration.
/// </summary>
public CCustomer() { }
/// <summary>
/// Construct a record for a given relational customer id
/// </summary>
public CCustomer(int id) : base(id) { }
/// <summary>
/// Expose the row key with a nicer property name
/// </summary>
public int CustomerId { get { return RowKey; } }
/// <summary>
/// Reference another Cassandra entity
/// </summary>
[CassandraRow] public CassandraRowReference<CImageContent> Photo;
}
[CassandraEntity("MyKeyspace", "MimeContent")]
public class CImageContent : CassandraEntity<byte[]>
{
public CImageContent() { }
public CImageContent(Bitmap b) : base(Hash(b)) { Image = b; }
static byte[] Hash(Bitmap b)
{
using (MemoryStream mstr = new MemoryStream())
{
b.Save(mstr, b.RawFormat);
byte[] bits = mstr.ToArray();
var hasher = System.Security.Cryptography.SHA1.Create();
return hasher.ComputeHash(bits);
}
}
[CassandraColumn("Dims", typeof(CustomConverters.SizeConverter))]
public Size Size;
[CassandraColumn("Mime")]
public string MimeType;
[CassandraColumn("Data")]
public Bitmap Image;
}
Now, we can save, read, and partially save these entities:
Bitmap b = (Bitmap) Image.FromFile(args[1]);
CImageContent img = new CImageContent(b);
img.MimeType = MimeType(args[1]);
img.Size = new Size(b.Width, b.Height);
CCustomer cust = new CCustomer(1);
cust.Photo = img;
using (var client = CassandraInterface.GetClient())
{
client.Save(ConsistencyLevel.ONE, img, cust);
var exCust = client.SelectByRowKey<CCustomer>(1);
// Load up the associated entity
exCust.Photo.EnsureValue(client);
// You can also save parts of an object
client.SavePartial(ConsistencyLevel.ONE, () => { img.MimeType, img.Data });
}