Deserializing IEnumerable with private support field in RavenDb

I’ve been modeling a domain for several days, and didn’t think about persistence at all, but instead I focused on the domain logic. Now I am ready to save domain objects, some of which contain IEnumerable child objects. Using RavenDb, resilience is "light", but when loading my objects all IEnumerables are empty again.

I realized that this is because they don’t have any properties at all, but instead use a list as a support field. The user of the domain’s root aggregate can add children through the public method, and not directly to the collection.

private readonly List<VeryImportantPart> _veryImportantParts; public IEnumerable<VeryImportantPart> VeryImportantParts { get { return _veryImportantParts; } } 

And the adding method, nothing unusual ...

 public void AddVeryImportantPart(VeryImportantPart part) { // some logic... _veryImportantParts.Add(part); } 

I can fix this by adding a private / secure setter to all of my IEnumerables with support fields, but it looks ... well ... not super sexy.

 private List<VeryImportantPart> _veryImportantParts; public IEnumerable<VeryImportantPart> VeryImportantParts { get { return _veryImportantParts; } protected set { _veryImportantParts = value.ToList(); } } 

Now the RavenDb json serializer will populate my objects again on boot, but I'm curious if there is a cleaner way to do this?

I searched for JsonContractResolver but haven't found a solution yet ...

+4
source share
2 answers

Do you need to keep a personal support field? Often an automatic property will do.

 public IList<VeryImportantPart> VeryImportantParts { get; protected set; } 

In this case, you can initialize your list in the constructor:

 VeryImportantParts = new List<VeryImportantPart>(); 

This, of course, is optional, but it allows you to create a new class and immediately add it to the list before it is saved. When Raven deserializes the class, it will use setter to overwrite the default empty list, so this just helps with the first repository.

Of course, you cannot use the readonly field, since it could not be replaced during deserialization. It may be possible to write a converter or contract converter that populates an existing list rather than creating a new one, but this seems like a rather complicated solution.

Using an automatic property can in any case add clarity to your code - since it is less confusing whether to use a field or property.

0
source

I think I found the root cause of this problem, and this is probably due to the fact that many of my entities were created using:

 protected MyClass(Guid id, string name, string description) : this() { .... } public static MyClass Create(string name, string description) { return new MyClass(Guid.NewGuid(), name, description); } 

During deserialization, RavenDb / Json.net was unable to properly rebuild my objects ...

Switching to using a public constructor did everything possible.

0
source

All Articles