Skip to content
mbdavid edited this page Jul 24, 2016 · 16 revisions

LiteDB supports POCO classes to strongly type documents. When you get a LiteCollection instance from LiteDatabase.GetCollection<T>, <T> will be your document type. If <T> is not a BsonDocument, LiteDB internally maps your class to BsonDocument. To do this, LiteDB uses the BsonMapper class:

// Simple strongly-typed document
public class Customer
{
    public ObjectId CustomerId { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
    public List<Phone> Phones { get; set; }
    public bool IsActive { get; set; }
}

var typedCustomerCollection = db.GetCollection<Customer>("customer");

var schemelessCollection = db.GetCollection("customer"); // <T> is BsonDocument

Mapper conventions

BsonMapper.ToDocument() auto converts each property of a class to a document field following these conventions:

  • Classes must be public with a public parameterless constructor
  • Properties must be public
  • Properties can be read-only or read/write
  • The class must have an Id property, <ClassName>Id property or any property with [BsonId] attribute or mapped by fluent api.
  • A property can be decorated with [BsonIgnore] to not be mapped to a document field
  • A property can be decorated with [BsonField] to customize the name of the document field
  • No circular references are allowed
  • Max depth of 20 inner classes
  • Class fields are not converted to document
  • You can use BsonMapper global instance (BsonMapper.Global) or a custom instance and pass to LiteDatabase in constructor. Keep this instance in a single place to avoid re-creating all mapping each time you use database.

In addition to basic BSON types, BsonMapper maps others .NET types to BSON data type:

.NET type BSON type
Int16, UInt16, Byte Int32
UInt32 , UInt64 Int64
Single, Decimal Double
Char, Enum String
IList<T> Array
T[] Array
NameValueCollection Document
IDictionary<K,T> Document
Any other .NET type Document
  • Nullable<T> are accepted. If value is null the BSON type is Null, otherwise the mapper will use T?.
  • For IDictionary<K, T>, K key must be String or simple type (convertible using Convert.ToString(..)).

Register a custom type

You can register your own map function, using the RegisterType<T> instance method. To register, you need to provide both serialize and deserialize functions.

BsonMapper.Global.RegisterType<Uri>
(
    serialize: (uri) => uri.AbsoluteUri,
    deserialize: (bson) => new Uri(bson.AsString)
);
  • serialize functions pass a <T> object instance as the input parameter and expect return a BsonValue
  • deserialize function pass a BsonValue object as the input parameter and except return a <T> value
  • RegisterType supports complex objects via BsonDocument or BsonArray

Mapping options

BsonMapper class settings:

Name Default Description
SerializeNullValues false Serialize field if value is null
TrimWhitespace true Trim strings properties before mapping to document
EmptyStringToNull true Empty strings convert to null
ResolvePropertyName (s) => s A function to map property name to document field name

BsonMapper offers 2 predefined functions to resolve property name: UseCamelCase() and UseLowerCaseDelimiter('_').

BsonMapper.Global.UseLowerCaseDelimiter('_');

public class Customer
{
    public int CustomerId { get; set; }

    public string FirstName { get; set; }

    [BsonField("customerLastName")]
    public string LastName { get; set; }
}

var doc = BsonMapper.Global.ToDocument(new Customer { FirstName = "John", LastName = "Doe" });

var id = doc["_id"].AsInt;
var john = doc["first_name"].AsString;
var doe = doc["customerLastName"].AsString;

AutoId

By default, typed documents will receive an auto Id value on insert. LiteDB support auto-id for this data types:

.NET data type New Value
ObjectId ObjectId.NewObjectId()
Guid Guid.NewGuid()
Int32 Auto-increment, per collection, starting in 1

But if you don't want to use any of the built-in methods, or want to use another data type for Id, you can set it yourself:

var customer = new Customer { Id = "john-doe", Name = "John Doe" };

You also can create your own auto-id function, using RegisterAutoId<T>:

BsonMapper.Global.RegisterAutoId<long>
(
    isEmpty: (value) => value == 0,
    newId: (collection) => DateTime.UtcNow.Ticks
);

public class Calendar
{
    public long CalendarId { get; set; }
}
  • isEmpty returns true to indicate when this type is considered empty. In this example, zero will be an empty value.
  • newId returns a new id value. It takes a LiteCollection<BsonDocument> instance as an input parameter that you may use to determine the new Id. In this example, the collection is ignored and the current Ticks value is returned.

Index definition

BsonMapper supports index definition directly on a property using the [BsonIndex] attribute. You can define index options like Unique or IgnoreCase. This allows you to avoid always needing to call col.EnsureIndex("field") before running a query.

public class Customer
{
    public int Id { get; set; }
    
    [BsonIndex]
    public string Name { get; set; }
    
    [BsonIndex(unique: true, removeAccents: false)]
    public string Email { get; set; }
}

IndexOptions class settings:

Name Default Description
Unique false Do not allow duplicates values in index
IgnoreCase true Store string on index in lowercase
RemoveAccents true Store string on index removing accents
TrimWhitespace true Store string on index removing trimming spaces
EmptyStringToNull true If string is empty, convert to Null

To get better performance, [BsonIndex] checks only if the index exists, but does not check if you are changing options. To change an index option in a existing index you must run EnsureIndex with the new index options. This method drops the current index and creates a new one with the new options.

Do not use [BsonIndex] attribute on your Id primary key property. This property already has an unique index with the default options.

Fluent Mapping

In v2, LiteDB offers a complete fluent API to create custom mapping without using attributes, keeping you domain classes without external references.

Fluent API use EntityBuilder to add custom mappings to your classes.

var mapper = BsonMapper.Global;

mapper.Entity<MyEntity>()
    .Id(x => x.MyCustomKey) // set your document ID
    .Ignore(x => x.DoNotSerializeThis) // ignore this property (do not store)
    .Field(x => x.CustomerName, "cust_name") // rename document field
    .Index(x => x.Address.Number, true); // create unique index