Litedb: [QUESTION] v5 Example of how to use custom serializers?

Created on 29 Mar 2020  路  5Comments  路  Source: mbdavid/LiteDB

Hello, I'm a newbie to LiteDB and currently evaluating it for my purposes.
I've tried to refer to the documentation, however it seems a lot of it is for v4 which is apparently out-of-date?

My question related to whether there is a concrete example of how to perform a customized de/serialization of any object.

My classes will be used by external developers, so I do not wish to decorate classes with LiteDB-specific tags.

As such, how would I go about persisting a class such as this:

public class Record 
{
   string Field1 {get; set;}
   string Field2 {get; set;}
   [NonSerialized]
   string DontPersistField { get; set; }
}

Note that the class has no 'Id' field and I would like to omit 'DontPersistField' from being stored (it is marked as 'NonSerialized').

What is the correct way of persisting this in LiteDB without having to alter my class structure?

Thanks!

question

Most helpful comment

@devmaestro1 If you want a solution that ignores fields with NonSerializedAttribute and works for any type, you could create a custom mapper class that inherits from BsonMapper and overrides GetTypeMembers:

```C#
public class MyMapper : BsonMapper
{
protected override IEnumerable GetTypeMembers(Type type)
{
return base.GetTypeMembers(type).Where(m => !m.IsDefined(typeof(NonSerializedAttribute), true));
}
}

//Usage
var mapper = new MyMapper();
mapper.IncludeFields = true; //the mapper only serializes properties by default
//this command is needed to serialize fields too
using var db = new LiteDatabase("database.db", mapper);


>- Is there an intention to support standard "ISerialization"-type functionality and attributes (eg. Serialize/Deserialize)?
>- Is there any interface supported by LiteDb (such as "ISerializable") that would allow each class to define how it should be serialized rather than having it centralized in the Mapper class?

LiteDB does not support these features currently, however they could be considered for the future.

>- Is there any method that is called after serialization/deserialization so I can perform any additional "cleanup" tasks on the object prior to its use?

You could achieve this with custom serializers and deserializers:

```C#
mapper.RegisterType<MyClass>
(
    serialize: o =>
    {
        var doc = new BsonDocument();
        doc["_id"] = o.Id;
        doc["Field1"] = o.Field1;
        //whatever you want to do
        return doc;
    },
    deserialize: doc =>
    {
        var o = new MyClass();
        o.Id = doc["_id"];
        o.Field1 = doc["Field1"];
        //whatever you want to do
        return o;
    }
);

All 5 comments

@devmaestro1 The updated documentation for v5 can be found in our website.

You should do something like this:
C# var mapper = BsonMapper.Global; mapper.Entity<Record>().Ignore(x => x.DontPersistField);
This would configure the global mapper to ignore this field upon storage.

The lack of id field shouldn't be a problem. LiteDB will use auto id to store the documents (of type ObjectId by default, but it can be changed to Guid, Int32 or Int64) and the id field will be ignored upon retrieval.

Hi @lbnascimento, Thank you for your quick response.

I've gone through the documentation relating to custom types but still lacking an understanding of how I would implement this while only exposing "standard" attributes to developers who are implementing my interface. The example you gave requires that the developer has access to the BsonMapper instance which I intend to not expose to developers (i.e. I am developing a configuration that developers can add new classes to but wont have access to the underlying persistence mechanism).

Some related questions:

  • Is there some way I can ignore fields with a specific Attribute (such as 'NonSerialized')?
  • Is there an intention to support standard "ISerialization"-type functionality and attributes (eg. Serialize/Deserialize)?
  • Is there any interface supported by LiteDb (such as "ISerializable") that would allow each class to define how it should be serialized rather than having it centralized in the Mapper class?
  • Is there any method that is called after serialization/deserialization so I can perform any additional "cleanup" tasks on the object prior to its use?
  • If not, is there any recommendation you have on how to do all this?

Of course, please let me know if I am going beyond the scope of what LiteDB was intended. ;)

Thank you!

I might have answered at least question 1. Perhaps this will work to ignore all fields with the "NonSerialized" attribute:

var mapper = BsonMapper.Global;
mapper.Entity<Record>().Ignore(x => Attribute.GetCustomAttributes(typeof(NonSerializedAttribute), true));

@devmaestro1 If you want a solution that ignores fields with NonSerializedAttribute and works for any type, you could create a custom mapper class that inherits from BsonMapper and overrides GetTypeMembers:

```C#
public class MyMapper : BsonMapper
{
protected override IEnumerable GetTypeMembers(Type type)
{
return base.GetTypeMembers(type).Where(m => !m.IsDefined(typeof(NonSerializedAttribute), true));
}
}

//Usage
var mapper = new MyMapper();
mapper.IncludeFields = true; //the mapper only serializes properties by default
//this command is needed to serialize fields too
using var db = new LiteDatabase("database.db", mapper);


>- Is there an intention to support standard "ISerialization"-type functionality and attributes (eg. Serialize/Deserialize)?
>- Is there any interface supported by LiteDb (such as "ISerializable") that would allow each class to define how it should be serialized rather than having it centralized in the Mapper class?

LiteDB does not support these features currently, however they could be considered for the future.

>- Is there any method that is called after serialization/deserialization so I can perform any additional "cleanup" tasks on the object prior to its use?

You could achieve this with custom serializers and deserializers:

```C#
mapper.RegisterType<MyClass>
(
    serialize: o =>
    {
        var doc = new BsonDocument();
        doc["_id"] = o.Id;
        doc["Field1"] = o.Field1;
        //whatever you want to do
        return doc;
    },
    deserialize: doc =>
    {
        var o = new MyClass();
        o.Id = doc["_id"];
        o.Field1 = doc["Field1"];
        //whatever you want to do
        return o;
    }
);

Thank you very much for your response on this. It has really helped me understand LiteDB a lot better.

Was this page helpful?
0 / 5 - 0 ratings