MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

JSON .NET персонализиран преобразувател на имена за под-свойства

Това, което можете да направите, е за въпросното свойство да създадете персонализиран JsonConverter който сериализира въпросната стойност на свойството с помощта на различен JsonSerializer създаден с различен преобразувател на договори, като така:

public class AlternateContractResolverConverter : JsonConverter
{
    [ThreadStatic]
    static Stack<Type> contractResolverTypeStack;

    static Stack<Type> ContractResolverTypeStack { get { return contractResolverTypeStack = (contractResolverTypeStack ?? new Stack<Type>()); } }

    readonly IContractResolver resolver;

    JsonSerializerSettings ExtractAndOverrideSettings(JsonSerializer serializer)
    {
        var settings = serializer.ExtractSettings();
        settings.ContractResolver = resolver;
        settings.CheckAdditionalContent = false;
        if (settings.PreserveReferencesHandling != PreserveReferencesHandling.None)
        {
            // Log an error throw an exception?
            Debug.WriteLine(string.Format("PreserveReferencesHandling.{0} not supported", serializer.PreserveReferencesHandling));
        }
        return settings;
    }

    public AlternateContractResolverConverter(Type resolverType)
    {
        if (resolverType == null)
            throw new ArgumentNullException("resolverType");
        resolver = (IContractResolver)Activator.CreateInstance(resolverType);
        if (resolver == null)
            throw new ArgumentNullException(string.Format("Resolver type {0} not found", resolverType));
    }

    public override bool CanRead { get { return ContractResolverTypeStack.Count == 0 || ContractResolverTypeStack.Peek() != resolver.GetType(); } }
    public override bool CanWrite { get { return ContractResolverTypeStack.Count == 0 || ContractResolverTypeStack.Peek() != resolver.GetType(); } }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException("This contract resolver is intended to be applied directly with [JsonConverter(typeof(AlternateContractResolverConverter), typeof(SomeContractResolver))] or [JsonProperty(ItemConverterType = typeof(AlternateContractResolverConverter), ItemConverterParameters = ...)]");
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        using (ContractResolverTypeStack.PushUsing(resolver.GetType()))
            return JsonSerializer.CreateDefault(ExtractAndOverrideSettings(serializer)).Deserialize(reader, objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        using (ContractResolverTypeStack.PushUsing(resolver.GetType()))
            JsonSerializer.CreateDefault(ExtractAndOverrideSettings(serializer)).Serialize(writer, value);
    }
}

internal static class JsonSerializerExtensions
{
    public static JsonSerializerSettings ExtractSettings(this JsonSerializer serializer)
    {
        // There is no built-in API to extract the settings from a JsonSerializer back into JsonSerializerSettings,
        // so we have to fake it here.
        if (serializer == null)
            throw new ArgumentNullException("serializer");
        var settings = new JsonSerializerSettings
        {
            CheckAdditionalContent = serializer.CheckAdditionalContent,
            ConstructorHandling = serializer.ConstructorHandling,
            ContractResolver = serializer.ContractResolver,
            Converters = serializer.Converters,
            Context = serializer.Context,
            Culture = serializer.Culture,
            DateFormatHandling = serializer.DateFormatHandling,
            DateFormatString = serializer.DateFormatString,
            DateParseHandling = serializer.DateParseHandling,
            DateTimeZoneHandling = serializer.DateTimeZoneHandling,
            DefaultValueHandling = serializer.DefaultValueHandling,
            EqualityComparer = serializer.EqualityComparer,
            // No Get access to the error event, so it cannot be copied.
            // Error = += serializer.Error
            FloatFormatHandling = serializer.FloatFormatHandling,
            FloatParseHandling = serializer.FloatParseHandling,
            Formatting = serializer.Formatting,
            MaxDepth = serializer.MaxDepth,
            MetadataPropertyHandling = serializer.MetadataPropertyHandling,
            MissingMemberHandling = serializer.MissingMemberHandling,
            NullValueHandling = serializer.NullValueHandling,
            ObjectCreationHandling = serializer.ObjectCreationHandling,
            ReferenceLoopHandling = serializer.ReferenceLoopHandling,
            // Copying the reference resolver doesn't work in the default case, since the
            // actual BidirectionalDictionary<string, object> mappings are held in the 
            // JsonSerializerInternalBase.
            // See https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
            ReferenceResolverProvider = () => serializer.ReferenceResolver,
            PreserveReferencesHandling = serializer.PreserveReferencesHandling,
            StringEscapeHandling = serializer.StringEscapeHandling,
            TraceWriter = serializer.TraceWriter,
            TypeNameHandling = serializer.TypeNameHandling,
            // Changes in Json.NET 10.0.1
            //TypeNameAssemblyFormat was obsoleted and replaced with TypeNameAssemblyFormatHandling in Json.NET 10.0.1
            //TypeNameAssemblyFormat = serializer.TypeNameAssemblyFormat,
            TypeNameAssemblyFormatHandling = serializer.TypeNameAssemblyFormatHandling,
            //Binder was obsoleted and replaced with SerializationBinder in Json.NET 10.0.1
            //Binder = serializer.Binder,
            SerializationBinder = serializer.SerializationBinder,
        };
        return settings;
    }
}

public static class StackExtensions
{
    public struct PushValue<T> : IDisposable
    {
        readonly Stack<T> stack;

        public PushValue(T value, Stack<T> stack)
        {
            this.stack = stack;
            stack.Push(value);
        }

        // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
        public void Dispose()
        {
            if (stack != null)
                stack.Pop();
        }
    }

    public static PushValue<T> PushUsing<T>(this Stack<T> stack, T value)
    {
        if (stack == null)
            throw new ArgumentNullException();
        return new PushValue<T>(value, stack);
    }
}

След това го използвайте така:

public class RootObject
{
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }

    [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy))]
    [JsonConverter(typeof(AlternateContractResolverConverter), typeof(DefaultContractResolver))]
    public SomeDocument SomeDocument { get; set; }
}

public class SomeDocument
{
    public string MyFirstProperty { get; set; }
    public string mysecondPROPERTY { get; set; }
    public AnotherRandomSubdoc another_random_subdoc { get; set; }
}

public class AnotherRandomSubdoc
{
    public string evenmoredata { get; set; }
    public DateTime DateCreated { get; set; }
}

(Тук предполагам, че искате "SomeDocument" името на свойството да бъде сериализирано дословно, въпреки че не беше напълно ясно от въпроса ви. За да направя това, използвам JsonPropertyAttribute.NamingStrategyType от Json.NET 9.0.1. Ако използвате по-ранна версия, ще трябва да зададете изрично името на свойството.)

Тогава полученият JSON ще бъде:

{
  "name": "Question 40597532",
  "dateCreated": "2016-11-14T05:00:00Z",
  "SomeDocument": {
    "MyFirstProperty": "my first property",
    "mysecondPROPERTY": "my second property",
    "another_random_subdoc": {
      "evenmoredata": "even more data",
      "DateCreated": "2016-11-14T05:00:00Z"
    }
  }
}

Имайте предвид, че това решение НЕ работи добре с запазване на препратки към обекти . Ако имате нужда от тях да работят заедно, може да се наложи да обмислите подход, базиран на стека, подобен на този от Json.NET сериализира по дълбочина и атрибут

Демо цигулка тук .

Между другото, обмисляли ли сте да съхраните този JSON като необработен низов литерал, както в отговора на този въпрос ?



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Разбиране на MongoDB Aggregate и GroupBy

  2. Възможно ли е да има състояние в популацията на мангуста

  3. Как да върна стойностите на варианта на всеки продукт, ако този продукт е вариант?

  4. Как да използвам guid в заявка за обвивка на mongodb

  5. Как да получите данни от mongodb между включването на два дни в mongodb с помощта на mongoose