Search code examples
c#.netcassandradatastax-csharp-driver

Using private fields with the Cassandra C# driver


I'm trying to migrate one of my modules from Postgres (with EF) to Cassandra. Here is my best try for Cassandra mappings:

internal sealed class UserMappings : Mappings
{
    public UserMappings()
    {
        For<User>().TableName("users")
            .PartitionKey(x => x.Id)
            .ClusteringKey(x => x.Id)
            .Column(x => x.Id, x => x.WithDbType<Guid>().WithName("id"))
// I want to add mappings for password Hash here

    }
}

The first problem is that I use VO for completive safety but want to store primitives in database. Example VO for entity id:

public record UserId
{
    public Guid Value { get; }

    public UserId(Guid value)
    {
        if (value == Guid.Empty) throw new Exception("Invalid UserId");
        Value = value;
    }
    
    public static implicit operator Guid(UserId id) => id.Value;
    public static implicit operator UserId(Guid id) => new(id);
    
}

Secondly, my entity has private fields and I don't know how to map them to the database.

internal class User
{
    private User()
    {
    }

    public User(/*...*/)
    {
        //...
    }
    private string _passwordHash;
    public UserId Id { get; }
    
    //...
}

Also is public parameterless constructor required?


Solution

  • It sounds like you want to have some business logic in the classes that you are using to map to your database. I would recommend creating new classes that have only public properties and no logic whatsoever (i.e. POCOs) and then mapping these objects into your domain objects either "manually" or with a library like AutoMapper. This has the benefit of keeping your domain objects separate from the database schema.

    The DataStax C# driver mapper will not be able to map private fields or properties that don't have a setter. It is able to map properties with a private setter though so you might want to leverage that instead.

    Also keep in mind that you will need to provide a custom TypeConverter to the Mapper or Table objects if you use custom types in your mapping. You might get away with not implementing a TypeConveter if you have implicit operators to convert these types (like your UserId class) but I'm not 100% sure.

    On the constructor issue, I think having a private empty constructor is enough.