Daniel Robinson
Daniel Robinson

Reputation: 14878

Default MongoDB serialization of public properties

I understand that I must have public read and write properties on my class for MongoDB driver to serialize/deserialize my objects. however I want to know whether there is method/preferred method for hiding the write properties from the rest of my code?

eg.

class Product
{
    private List<Release> releases;

    public List<Release> Releases
    {
        get
        {
            return new List<Release>(releases); //I can protect 'releases' when reading by passing a copy of it
        }
        set
        {
            releases = value; //BUT how can I protect release when writing?
        }
    }
}

I want MongoDB to be able to serialize/deserialize my types but I don't want the rest of my code to be able to overwrite it's fields / properties that should otherwise have been private. Is there a pattern to handle this? I have thought about having a separate ProductDoc class which is just used as a intermediary for getting Product objects into and out of MongoDB, but I'm not sure whether there is a better solution to this.

Upvotes: 5

Views: 5076

Answers (3)

Ian Mercer
Ian Mercer

Reputation: 39277

Another approach, if your properties are set by the constructor is to keep them read only and to use MapCreator to tell MongoDB how to create an instance of your class passing in the properties you want to set.

e.g. I have a class called Time with three readonly properties: Hour, Minute and Second and a public constructor that takes an hour, a minute and a second value.

Here's how I get MongoDB to store those three values in the database and to construct new Time objects during deserialization.

BsonClassMap.RegisterClassMap<Time>(cm =>
{
    cm.AutoMap();
    cm.MapCreator(p => new Time(p.Hour, p.Minute, p.Second));
    cm.MapProperty(p => p.Hour);
    cm.MapProperty(p => p.Minute);
    cm.MapProperty(p => p.Second);
}

Upvotes: 2

TGardner
TGardner

Reputation: 176

The best answer on this page currently has some flaws which are important to understand.

As the solution is currently written:

public List<Release> Releases
{
    get
    {
        return new List<Release>(releases); //I can protect 'releases' when reading by passing a copy of it
    }
    protected set
    {
        releases = value; //BUT how can I protect release when writing?
    }
}

This doesn't work as written.

obj.Releases.Add(new Release());

Would affect the underlying collection by adding a new release to it. Which is in direct contradiction to the stated goal of making the set routine private.

However if you change the exposed property type to implement IEnumerable instead of List and return a ReadOnly version of the list. Such as...

public IEnumerable<Release> Releases
{
    get
    {
        return new List<Release>(releases).AsReadOnly();
    }
    protected set
    {
        releases = value;
    }
}

Then both

obj.Releases.Add(new Release());

and

obj.Releases = new List<Release>();

will both throw build errors and prevent modifying the underlying collection.

Upvotes: 1

petro.sidlovskyy
petro.sidlovskyy

Reputation: 5103

I have not worked with mongo for a long time for now. But you may try to read this thread MongoDb Map Setters or try to make your setter protected like this:

public List<Release> Releases
{
    get
    {
        return new List<Release>(releases); //I can protect 'releases' when reading by passing a copy of it
    }
    protected set
    {
        releases = value; //BUT how can I protect release when writing?
    }
}

Upvotes: 5

Related Questions