Tuesday, October 9, 2012

Strongly-typed id for MongoDb C# driver

MongoDb C# driver already has a lot of features however it still can be improved.
One particular idea is to use strongly typed id field instead of generic ObjectId type which will lead to checking correct id type at a compile-time and not in a run-time. For example, using id of this type you can ensure that you pass id of a product to a GetProductById method. Here is how it can be implemented (requires MongoDb c# driver) :
public class Id<T> : IEquatable<IId<T>>
{
public ObjectId Value { get;private set; }
public override string ToString()
{
return Value.ToString();
}
public Id(ObjectId value)
{
Value = value;
}
public static Id<T> GetNew()
{
return new Id<T>(ObjectId.GenerateNewId());
}
#region generated
public bool Equals(Id<T> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.Value.Equals(Value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof(Id<T>)) return false;
return Equals((Id<T>)obj);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public static bool operator ==(Id<T> left, Id<T> right)
{
return Equals(left, right);
}
public static bool operator !=(Id<T> left, Id<T> right)
{
return !Equals(left, right);
}
public bool Equals(IId<T> other)
{
return Equals((object)other);
}
#endregion
}
view raw id.cs hosted with ❤ by GitHub
MongoDb requires id fields to be initialized when document is saved to database and in order to make developer's life easier and the code cleaner they provide mechanism for generation id when it does not exist. Here is its implementation for id:
public class IdGenerator<T> : IIdGenerator
{
public object GenerateId(object container, object document)
{
return Id<T>.GetNew();
}
public bool IsEmpty(object id)
{
var casted = id as Id<T>;
return casted == null || casted.Value == ObjectId.Empty;
}
}
view raw generator.cs hosted with ❤ by GitHub
After that id field can be declared in a following way. Note that after generator attribute has been set there is no need to set product id in a product constructor - it will be created when entity is saved to the database.
public class Product
{
[BsonId(IdGenerator = typeof(IdGenerator<Product>))]
public Id<Product> Id { get; private set; }
public string Name { get; set; }
public Decimal Price { get; set; }
}
view raw product.cs hosted with ❤ by GitHub

No comments:

Post a Comment