4

Could someone suggest a method of updating the items in the Cheese.Producers list?

I have the following classes:

class Producer
{
    public string Name { get; set; }
    public int Rating { get; set; }

    public Producer()
    {
    }

    public Producer(string name, int rating)
    {
        Name = name;
        Rating = rating;
    }
}

class Cheese
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Taste { get; set; }
    public List<Producer> Producers { get; set; }

    public Cheese()
    {
        Producers = new List<Producer>();
    }

    public Cheese(string name, int age)
    {
        Name = name;
        Age = age;
        Producers = new List<Producer>();
    }

    public Cheese(string name, int age, string taste)
    {
        Name = name;
        Age = age;
        Taste = taste;
        Producers = new List<Producer>();
    }
}

In the main code I have an object(gouda) that I want to update based on a JSON read from a file.

static void Main(string[] args)
{
    Producer prod1 = new Producer("prod1", 5);
    Producer prod2 = new Producer("prod2", 6);
    Producer prod3 = new Producer("prod3", 7);

    Cheese gouda = new Cheese("Gouda", 5, "Mild");
    gouda.Producers.Add(prod1);
    gouda.Producers.Add(prod2);
    gouda.Producers.Add(prod3);

    string propertiesToBeAdded = File.ReadAllText("properties.txt");
    JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
    {
        ObjectCreationHandling = ObjectCreationHandling.Reuse
    };
    JsonConvert.PopulateObject(propertiesToBeAdded, gouda, jsonSerializerSettings);
}

The JSON update file:

{
  "Name": "Hard Blue",
  "Taste": "Sharp",
  "Producers": [
    {
      "Name": "prod1",
      "Rating": 100
    },
    {
      "Name": "prod3",
      "Rating": 300
    }
  ]
}

The major problem is that when the PopulateObject is called, instead of updating the Producers list items, 2 new members are added. The other fields seem to work just fine. Any suggestions?

7
  • ObjectCreationHandling.Replace ? see stackoverflow.com/questions/31025153/… Commented Jul 14, 2015 at 9:47
  • Cheese partialCheese = JsonConvert.DeserializeObject<Cheese>(propertiesToBeAdded) isn't populating desired result I guess. Commented Jul 14, 2015 at 9:53
  • I tried using ObjectCreationHandling.Replace but instead of updating the first and the third producers it clears the list and insert the values specified in the Json file, so I end up with only 2 producers instead of 3. Commented Jul 14, 2015 at 10:59
  • what is your expected output? Commented Jul 14, 2015 at 11:00
  • { "Name": "Hard Blue", "Age": 5, "Taste": "Sharp", "Producers": [ { "Name": "prod1", "Rating": 100 }, { "Name": "prod2", "Rating": 6 }, { "Name": "prod3", "Rating": 300 } ] } Commented Jul 14, 2015 at 11:06

2 Answers 2

1

Try this:

                Producer prod1 = new Producer("prod1", 5);
                Producer prod2 = new Producer("prod2", 6);
                Producer prod3 = new Producer("prod3", 7);

                Cheese gouda = new Cheese("Gouda", 5, "Mild");
                gouda.Producers.Add(prod1);
                gouda.Producers.Add(prod2);
                gouda.Producers.Add(prod3);

                var propertiesToBeAdded = File.ReadAllText(@"C:\json path");
                
                var settings = new JsonMergeSettings
                {
                    MergeArrayHandling = MergeArrayHandling.Merge
                };

                var o1 = JObject.Parse(JsonConvert.SerializeObject(gouda));

                o1.Merge(JObject.Parse(propertiesToBeAdded), settings);

                var o = o1.ToString();

And you need to change your JSON format a bit :

{
  'Name': 'Hard Blue',
  'Taste': 'Sharp',
  'Producers': [
    {
      'Name': 'prod1',
      'Rating': 100
    },
    {
      
    },
    {
      'Name': 'prod3',
      'Rating': 300
    }
  ]
}

Here we go:

enter image description here

Hope this helps.

Sign up to request clarification or add additional context in comments.

2 Comments

It works in deed, thank you for your help. Now I can't help but wonder how costly is the extra serialization operation for very large objects.
you're serializing only once, that is minimal.
1

I feel there is no way to accomplish simply what you want to do, with the constraints of the format you're using.

You want to retain unique producers, but are using an array of producers, wich has no way of preserving uniqueness.

So, AFAICT, you have two roads.

1 - you change the producers array in an json object, which would deserialize as a dictionary.

2 - you restrict the use of JSON.NET to the deserialization, and then implement a method "merge" in your Cheese class, with the relevant uniqueness checks.

If you need a refinement over this directions, let me know.

EDIT

First, change your Cheese class into this:

class Cheese
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Taste { get; set; }
    public Dictionary<String, Producer> Producers { get; set; }

    public Cheese()
    {
        Producers = new Dictionary<String, Producer>();
    }

    public Cheese(string name, int age)
    {
        Name = name;
        Age = age;
        Producers = new List<Producer>();
    }

    public Cheese(string name, int age, string taste)
    {
        Name = name;
        Age = age;
        Taste = taste;
        Producers = new List<Producer>();
    }
}

And your Json accordingly:

{
  "Name": "Hard Blue",
  "Taste": "Sharp",
  "Producers": {
    "prod1": {
      "Name": "prod1",
      "Rating": 100
    },
    "prod3": {
      "Name": "prod3",
      "Rating": 300
    }
  }
}

Everything else should be equal. The nice thing about the dictionary is that it takes care of the uniqueness of the keys.

I left some redundancy in the data, to simplify the code. You could remove the

"Name": "prod1",
...
"Name": "prod3",

lines from the Json, populating the corresponding name property after deserialization, something like:

foreach(var prod in gouda.Producers.Keys)
{
  gouda.Producers[prod].Name = prod;
}

Hope it helps.

1 Comment

The first option sounds pretty good. Could you please give me more details?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.