How can I create a JsonPatchDocument from comparing two c# objects?

前端 未结 3 1775
醉话见心
醉话见心 2021-01-31 19:51

Given I have two c# objects of the same type, I want to compare them to create a JsonPatchDocument.

I have a StyleDetail class defined like this:

public         


        
相关标签:
3条回答
  • 2021-01-31 20:32

    You can use this

    You can install using NuGet, see SimpleHelpers.ObjectDiffPatch at NuGet.org

    PM> Install-Package SimpleHelpers.ObjectDiffPatch
    

    Use:

    StyleDetail styleNew = new StyleDetail() { Id = "12", Code = "first" };
    StyleDetail styleOld = new StyleDetail() { Id = "23", Code = "second" };
    var diff = ObjectDiffPatch.GenerateDiff (styleOld , styleNew );
    
    // original properties values
    Console.WriteLine (diff.OldValues.ToString());
    
    // updated properties values
    Console.WriteLine (diff.NewValues.ToString());
    
    0 讨论(0)
  • 2021-01-31 20:52

    You could use my DiffAnalyzer. It's based on reflection and you can configure the depth you want to analyze.

    https://github.com/rcarubbi/Carubbi.DiffAnalyzer

    var before = new User { Id = 1, Name="foo"};
    var after= new User  { Id = 2, Name="bar"};
    var analyzer = new DiffAnalyzer();
    var results = analyzer.Compare(before, after);
    
    0 讨论(0)
  • 2021-01-31 20:56

    Let's abuse the fact that your classes are serializable to JSON! Here's a first attempt at a patch creator that doesn't care about your actual object, only about the JSON representation of that object.

    public static JsonPatchDocument CreatePatch(object originalObject, object modifiedObject)
    {
        var original = JObject.FromObject(originalObject);
        var modified = JObject.FromObject(modifiedObject);
    
        var patch = new JsonPatchDocument();
        FillPatchForObject(original, modified, patch, "/");
    
        return patch;
    }
    
    static void FillPatchForObject(JObject orig, JObject mod, JsonPatchDocument patch, string path)
    {
        var origNames = orig.Properties().Select(x => x.Name).ToArray();
        var modNames = mod.Properties().Select(x => x.Name).ToArray();
    
        // Names removed in modified
        foreach (var k in origNames.Except(modNames))
        {
            var prop = orig.Property(k);
            patch.Remove(path + prop.Name);
        }
    
        // Names added in modified
        foreach (var k in modNames.Except(origNames))
        {
            var prop = mod.Property(k);
            patch.Add(path + prop.Name, prop.Value);
        }
    
        // Present in both
        foreach (var k in origNames.Intersect(modNames))
        {
            var origProp = orig.Property(k);
            var modProp = mod.Property(k);
    
            if (origProp.Value.Type != modProp.Value.Type)
            {
                patch.Replace(path + modProp.Name, modProp.Value);
            }
            else if (!string.Equals(
                            origProp.Value.ToString(Newtonsoft.Json.Formatting.None),
                            modProp.Value.ToString(Newtonsoft.Json.Formatting.None)))
            {
                if (origProp.Value.Type == JTokenType.Object)
                {
                    // Recurse into objects
                    FillPatchForObject(origProp.Value as JObject, modProp.Value as JObject, patch, path + modProp.Name +"/");
                }
                else
                {
                    // Replace values directly
                    patch.Replace(path + modProp.Name, modProp.Value);
                }
            }       
        }
    }
    

    Usage:

    var patch = CreatePatch(
        new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "1", Removed = "1" },
        new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "2", Added = new { x = "1" } });
    
    // Result of JsonConvert.SerializeObject(patch)
    [
      {
        "path": "/Removed",
        "op": "remove"
      },
      {
        "value": {
          "x": "1"
        },
        "path": "/Added",
        "op": "add"
      },
      {
        "value": "2",
        "path": "/Changed",
        "op": "replace"
      }
    ]
    
    0 讨论(0)
提交回复
热议问题