Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用AutoMapper、Json.NET或其他库使用Json字符串中的更改更新父属性和子属性_C#_Reflection_Json.net_Automapper - Fatal编程技术网

C# 使用AutoMapper、Json.NET或其他库使用Json字符串中的更改更新父属性和子属性

C# 使用AutoMapper、Json.NET或其他库使用Json字符串中的更改更新父属性和子属性,c#,reflection,json.net,automapper,C#,Reflection,Json.net,Automapper,我有一个场景,给我一个json字符串,其中只包含用户为给定父/子对象修改的属性 当给定这个字符串时,我需要加载原始对象并使用json字符串中的更改对其进行更新 示例类 public class ParentObject { public int ID { get; set; } public string Prop1 { get; set; } public string Prop2 { get; set; } public List<ChildObject

我有一个场景,给我一个json字符串,其中只包含用户为给定父/子对象修改的属性

当给定这个字符串时,我需要加载原始对象并使用json字符串中的更改对其进行更新

示例类

public class ParentObject
{
    public int ID { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public List<ChildObject> Children { get; set; }
}

public class ChildObject
{
    public int ID { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
}
然后,我必须用更改的属性“更新”“原始”对象

我可以使用反射来迭代“原始”对象的属性,然后将这些属性与Json字符串进行比较,但我想知道是否还有其他像AutoMapper这样的库可以更容易地做到这一点

Newton Json.NET合并看起来很有希望。

自动映射代码--大部分工作正常
此代码“几乎”的工作原理是,它确实映射父级和子级,但如果子级具有与父级同名的属性,则此代码将失败。
AKA ID字段未映射到子项上

// Configure the mapping
Mapper.Initialize(cfg => cfg.CreateMap<ExpandoObject, ParentObject>());

// Convert the JSon into a dynamic list
var sources = JsonConvert.DeserializeObject<List<dynamic>>(modifiedProperties);

// Iterate the list of changes
foreach (dynamic source in sources)
{
    // Get the source ID to pull the record from the database
    var sourceID = Convert.ToInt32(source.ID);

    // Simulate a DB call to get the original object
    var destination = originalObject;

    // Map the objects together
    var realDestination = Mapper.Map(source, destination);

    // ** OUTPUT **
    // realDestination.ID = 1 <-- THIS IS CORRECT
    // realDestination.Prop1 = "Prop 1 Changed" <-- THIS IS CORRECT
    // realDestination.Prop2 = "Prop 2 Original" <-- THIS IS CORRECT
    // realDestination.Children.FirstOrDefault().ID = 0 <-- THIS SHOULD BE 22 NOT 0
    // realDestination.Children.FirstOrDefault().PropA = "Prop A Changed" <-- THIS IS CORRECT
    // realDestination.Children.FirstOrDefault().PropB = null <-- THIS IS CORRECT
}
//配置映射
初始化(cfg=>cfg.CreateMap());
//将JSon转换为动态列表
var sources=JsonConvert.DeserializeObject(modifiedProperties);
//迭代更改列表
foreach(源中的动态源)
{
//获取源ID以从数据库中提取记录
var sourceID=Convert.ToInt32(source.ID);
//模拟DB调用以获取原始对象
var destination=原始对象;
//将对象映射到一起
var realDestination=Mapper.Map(源、目标);
//**产出**

//realDestination.ID=1我让AutoMapper和Json.NET都工作了。
下面是我正在使用的代码和测试数据

public class ParentObject
{
    public int ID { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public List<ChildObject> Children { get; set; }
}

public class ChildObject
{
    public int ID { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
}


// Original object before modifications
var originalObject = new ParentObject
{
    ID = 1,
    Prop1 = "Prop 1 Original",
    Prop2 = "Prop 2 Original",    
    Children = new List<ChildObject>() { new ChildObject {
                ID = 22,
                PropA = "Prop A Original"}
            }
};

// Get the modified properties
string modifiedProperties =
    @"[{
        ""ID"": 1,
        ""Prop1"": ""Prop 1 Changed"",
        ""Children"": [{
            ""ID"": 22,
            ""PropA"": ""Prop A Changed""
        }]
    }]";



/* AUTOMAPPER CODE */

// Convert the JSon into a dynamic list for AUTOMAPPER
var mapperSources = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ExpandoObject>>(modifiedProperties);

// Initialize mapper
AutoMapper.Mapper.Initialize(cfg => { });

// Iterate the list of changes for AUTOMAPPER
foreach (dynamic source in mapperSources)
{
    // Get the source ID to pull the record from the database
    var sourceID = Convert.ToInt32(source.ID);

    // Simulate a DB call to get the original object
    var destination = originalObject;

    // Map the objects together
    var realDestination = AutoMapper.Mapper.Map(source, destination);
}


/* JSON.NET CODE */

// Convert the JSon into a dynamic list for JSON.NET
Newtonsoft.Json.Linq.JArray sources = Newtonsoft.Json.Linq.JArray.Parse(modifiedProperties);

// Iterate the list of changes for JSON.NET
foreach (Newtonsoft.Json.Linq.JObject source in sources)
{
    // Get the source ID to pull the record from the database
    var sourceID = Convert.ToInt32(source["ID"]);

    // Simulate a DB call to get the original object
    var destination = originalObject;

    // convert the object into a JObject for merge
    Newtonsoft.Json.Linq.JObject tempDestination = Newtonsoft.Json.Linq.JObject.FromObject(destination);

    // Map the objects together
    tempDestination.Merge(source, new Newtonsoft.Json.Linq.JsonMergeSettings
    {
        // Using merge
        MergeArrayHandling = Newtonsoft.Json.Linq.MergeArrayHandling.Merge
    });

    var realDestination = tempDestination.ToObject<ParentObject>();
}


/* EXPECTED OUTPUT
    realDestination.ID = 1
    realDestination.Prop1 = "Prop 1 Changed"
    realDestination.Prop2 = "Prop 2 Original"
    realDestination.Children.FirstOrDefault().ID = 22
    realDestination.Children.FirstOrDefault().PropA = "Prop A Changed"
    realDestination.Children.FirstOrDefault().PropB = null
*/
公共类ParentObject
{
公共int ID{get;set;}
公共字符串Prop1{get;set;}
公共字符串Prop2{get;set;}
公共列表子项{get;set;}
}
公共类子对象
{
公共int ID{get;set;}
公共字符串PropA{get;set;}
公共字符串PropB{get;set;}
}
//修改前的原始对象
var originalObject=新的父对象
{
ID=1,
Prop1=“Prop1原件”,
Prop2=“Prop 2原件”,
Children=new List(){new ChildObject{
ID=22,
PropA=“Prop A Original”}
}
};
//获取修改后的属性
字符串修饰符属性=
@"[{
“ID”:1,
“Prop1”:“Prop1已更改”,
“儿童”:[{
“”ID“”:22,
“PropA”:“Prop A已更改”
}]
}]";
/*自动映射代码*/
//将JSon转换为AUTOMAPPER的动态列表
var mapperSources=Newtonsoft.Json.JsonConvert.DeserializeObject(modifiedProperties);
//初始化映射器
AutoMapper.Mapper.Initialize(cfg=>{});
//迭代AUTOMAPPER的更改列表
foreach(mapperSources中的动态源)
{
//获取源ID以从数据库中提取记录
var sourceID=Convert.ToInt32(source.ID);
//模拟DB调用以获取原始对象
var destination=原始对象;
//将对象映射到一起
var realDestination=AutoMapper.Mapper.Map(源、目标);
}
/*JSON.NET代码*/
//将JSon转换为JSon.NET的动态列表
Newtonsoft.Json.Linq.JArray sources=Newtonsoft.Json.Linq.JArray.Parse(modifiedProperties);
//迭代JSON.NET的更改列表
foreach(源代码中的Newtonsoft.Json.Linq.JObject源代码)
{
//获取源ID以从数据库中提取记录
var sourceID=Convert.ToInt32(source[“ID”]);
//模拟DB调用以获取原始对象
var destination=原始对象;
//将对象转换为要合并的作业对象
Newtonsoft.Json.Linq.JObject tempDestination=Newtonsoft.Json.Linq.JObject.FromObject(目的地);
//将对象映射到一起
tempDestination.Merge(源代码,新的Newtonsoft.Json.Linq.JsonMergeSettings
{
//使用合并
MergeArrayHandling=Newtonsoft.Json.Linq.MergeArrayHandling.Merge
});
var realDestination=tempDestination.ToObject();
}
/*预期产量
realDestination.ID=1
realditudio.Prop1=“Prop 1已更改”
realditudio.Prop2=“Prop 2原件”
realDestination.Children.FirstOrDefault().ID=22
realDestination.Children.FirstOrDefault().PropA=“道具A已更改”
realDestination.Children.FirstOrDefault().PropB=null
*/
我运行了一个.NET秒表,以下是我所知道的最好的“性能”结果。
如果有人注意到我的测试代码中有错误,请告诉我

Stopwatch sw = new Stopwatch();

for (int c = 0; c < 4; c++)
{
    sw.Restart();

    for (int i = 0; i < 500000; i++)
    {
        /* MAPPING CODE HERE */
    }

    sw.Stop();

    Console.WriteLine("Elapsed = {0}", sw.Elapsed);
}

/* STOPWATCH RESULTS 
    Elapsed AUTOMAPPER = 00:00:16.5727406
    Elapsed AUTOMAPPER = 00:00:16.8015508
    Elapsed AUTOMAPPER = 00:00:14.6642556
    Elapsed AUTOMAPPER = 00:00:13.9644693

    Elapsed JSON.NET = 00:00:18.8097409
    Elapsed JSON.NET = 00:00:17.6313278
    Elapsed JSON.NET = 00:00:18.6343426
    Elapsed JSON.NET = 00:00:18.8855448
*/
Stopwatch sw=新秒表();
对于(int c=0;c<4;c++)
{
sw.Restart();
对于(int i=0;i<500000;i++)
{
/*这里映射代码*/
}
sw.Stop();
WriteLine(“运行时间={0}”,sw.appeased);
}
/*秒表结果
经过的自动映射=00:00:16.5727406
已用自动映射=00:00:16.8015508
已用自动映射=00:00:14.6642556
已用自动映射=00:00:13.9644693
已用JSON.NET=00:00:18.8097409
已用JSON.NET=00:00:17.6313278
已用JSON.NET=00:00:18.6343426
已用JSON.NET=00:00:18.8855448
*/

AutoMapper是个好主意。说“它不起作用”是没有帮助的。显示你使用的代码并解释什么不起作用。可能对你有用。@Equalsk我已经添加了AutoMapper代码,但我不确定AutoMapper是正确的路径,因为我没有看到任何关于它的文档能够“合并”只是更改。再说一遍,你说“不起作用”,但不说实际发生了什么……我手头没有编写测试的工具,但我假设您需要类似于
CreateMap().ForAllMembers的东西(o=>o.Condition((src,dest,srcMember)=>srcMember!=null));
假设属性是引用类型。由于您没有显示类或示例值,我不得不猜测。@Equalsk您的代码看起来很有希望,但当我尝试时,我得到了一个新的“空”父对象
public class ParentObject
{
    public int ID { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public List<ChildObject> Children { get; set; }
}

public class ChildObject
{
    public int ID { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
}


// Original object before modifications
var originalObject = new ParentObject
{
    ID = 1,
    Prop1 = "Prop 1 Original",
    Prop2 = "Prop 2 Original",    
    Children = new List<ChildObject>() { new ChildObject {
                ID = 22,
                PropA = "Prop A Original"}
            }
};

// Get the modified properties
string modifiedProperties =
    @"[{
        ""ID"": 1,
        ""Prop1"": ""Prop 1 Changed"",
        ""Children"": [{
            ""ID"": 22,
            ""PropA"": ""Prop A Changed""
        }]
    }]";



/* AUTOMAPPER CODE */

// Convert the JSon into a dynamic list for AUTOMAPPER
var mapperSources = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ExpandoObject>>(modifiedProperties);

// Initialize mapper
AutoMapper.Mapper.Initialize(cfg => { });

// Iterate the list of changes for AUTOMAPPER
foreach (dynamic source in mapperSources)
{
    // Get the source ID to pull the record from the database
    var sourceID = Convert.ToInt32(source.ID);

    // Simulate a DB call to get the original object
    var destination = originalObject;

    // Map the objects together
    var realDestination = AutoMapper.Mapper.Map(source, destination);
}


/* JSON.NET CODE */

// Convert the JSon into a dynamic list for JSON.NET
Newtonsoft.Json.Linq.JArray sources = Newtonsoft.Json.Linq.JArray.Parse(modifiedProperties);

// Iterate the list of changes for JSON.NET
foreach (Newtonsoft.Json.Linq.JObject source in sources)
{
    // Get the source ID to pull the record from the database
    var sourceID = Convert.ToInt32(source["ID"]);

    // Simulate a DB call to get the original object
    var destination = originalObject;

    // convert the object into a JObject for merge
    Newtonsoft.Json.Linq.JObject tempDestination = Newtonsoft.Json.Linq.JObject.FromObject(destination);

    // Map the objects together
    tempDestination.Merge(source, new Newtonsoft.Json.Linq.JsonMergeSettings
    {
        // Using merge
        MergeArrayHandling = Newtonsoft.Json.Linq.MergeArrayHandling.Merge
    });

    var realDestination = tempDestination.ToObject<ParentObject>();
}


/* EXPECTED OUTPUT
    realDestination.ID = 1
    realDestination.Prop1 = "Prop 1 Changed"
    realDestination.Prop2 = "Prop 2 Original"
    realDestination.Children.FirstOrDefault().ID = 22
    realDestination.Children.FirstOrDefault().PropA = "Prop A Changed"
    realDestination.Children.FirstOrDefault().PropB = null
*/
Stopwatch sw = new Stopwatch();

for (int c = 0; c < 4; c++)
{
    sw.Restart();

    for (int i = 0; i < 500000; i++)
    {
        /* MAPPING CODE HERE */
    }

    sw.Stop();

    Console.WriteLine("Elapsed = {0}", sw.Elapsed);
}

/* STOPWATCH RESULTS 
    Elapsed AUTOMAPPER = 00:00:16.5727406
    Elapsed AUTOMAPPER = 00:00:16.8015508
    Elapsed AUTOMAPPER = 00:00:14.6642556
    Elapsed AUTOMAPPER = 00:00:13.9644693

    Elapsed JSON.NET = 00:00:18.8097409
    Elapsed JSON.NET = 00:00:17.6313278
    Elapsed JSON.NET = 00:00:18.6343426
    Elapsed JSON.NET = 00:00:18.8855448
*/