简体   繁体   中英

Override Json Serialization RavenDB

I am experimenting with RavenDB. We have a significant number of entity objects which are decorated with attributes as per the following (simple) example:

[Entity(UniqueID = "37AA8322-597D-48E8-BB66-7B2796103D95")]
public class SampleEntity : Entity
{
    protected SampleEntity()
    {

    }

    public static SampleEntity Create()
    {
        return EntityFactory.Create<SampleEntity>();
    }

    [Property]
    public virtual int Integer { get; set; }
}

The type emitted by EntityFactory is actually a sub-class of SampleEntity which overrides the setter/getter automatically implementing INotifyPropertyChanged and keeping track of when each property was last modified (among other things).

Using Json.NET I threw together a Json serializer for Entity's which, for an instance of SampleEntity with 'Integer' set to 8 would spit out something similar to the following:

{
  "TypeID": "\"37aa8322-597d-48e8-bb66-7b2796103d95\"",
  "UniqueID": "\"e1f03e21-260f-4bde-8bfb-ec7a47b2e379\"",
  "Integer": {
    "Last Set": "2014-09-30T14:06:08.9146417Z",
    "Value": "8"
  }
}

Notice how the 'Integer' property gets expanded to include both 'Value' and 'Last Set'. If I ask RavenDB to store a SampleEntity, I (as expected) don't get 'Last Set' inline with 'Value' (In the base class there is a dictionary mapping property names to information about the property, one field being when the property was last set).

Ideally, I would like to store the output of the Json-Entity serializer I wrote in RavenDB (with the UniqueID which gets automatically generated for each Entity as the document ID). When I retrieve a document, it would be raw json and I would be responsible for using that to hydrate the appropriate entity object. I have searched extensively and could not find an easy way to accomplish this, which historically has meant I'm trying to do something stupid.

I am new to both RavenDB (document databases in general) and Json, so perhaps I'm trying to jam a square peg into a round hole here and there is a more elegant way to handle the situation.

Does anybody know a way to store raw json in RavenDB? Or have any comments/suggestions on another way I can accomplish what I have described?

One option would be to use a converter to customize the RavenJObject that gets written to the database, and to customize the way that your desired return object gets filled.

Heres some code:

public class SampleEntityConverter : IDocumentConversionListener
{
    public void EntityToDocument(string key, object entity, RavenJObject document, RavenJObject metadata)
    {
        var obj = entity as SampleEntity;
        if (obj == null)
        {
            return;
        }

        var integer = new RavenJObject();
        integer["Last Set"] = obj.HoweverYouGetTheLastSetDateTime;
        integer["Value"] = obj.Integer;
        document["Integer"] = integer;
    }

    public void DocumentToEntity(string key, object entity, RavenJObject document, RavenJObject metadata)
    {
        var obj = entity as SampleEntity;
        if (obj == null)
        {
            return;
        }

        var integer = document["Integer"] as RavenJObject;       
        if (integer != null && integer.ContainsKey("Value"))
        {
            obj.Integer = integer["Value"];
        }
    }
}

Then register it on your DocumentStore instance:

documentStore.RegisterListener(new SampleEntityConverter());

You can register the same converter using the internalized copy of JSON.Net that RavenDB uses. In the Conventions, look at the CustomizeSerialize method

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM