将 C# 对象序列化为包含列表的 JSON

Serialize C# object into JSON which contains a List

我想做的是从我的数据库中获取一些数据(客户订购他订购的所有商品)将其转换为 JSON,其中包含所述商品的列表,以便我可以将其发送POST 请求。 我想创建一个 JSON 对象,其中包含客户订单的详细信息以及该订单中包含的产品列表。这就是我希望我的 JSON 看起来像的样子:

{
  "account_code": "00000",       
  "advance_payment": false,       
  "date": [today's date],
  "order_items": 
   [
     {
       "item_id": 0, 
       "product_Price ": "105.00",  
       "order_Item_Rebate: "",     
       "product_code": "000001",   
       "quantity": 1
     },
     {
       "item_id": 1, 
       "product_Price ": "55.00",  
       "price": "",     
       "product_code": "000002",   
       "quantity": 5
     },
     {
       "item_id": 2, 
       "product_Price ": "15.00",  
       "price": "",     
       "product_code": "000003",   
       "quantity": 3
     }
   ]
}

但我得到的是:

{
  "account_code": "00000",       
  "advance_payment": false,       
  "date": [today's date],
  "order_items": 
   [
     {
       "item_id": 0, 
       "roduct_Price ": "105.00",  
       "order_Item_Rebate: "",     
       "product_code": "000001",   
       "quantity": 1
     }
   ]
},
{
  "account_code": "00000",       
  "advance_payment": false,       
  "date": [today's date],
  "order_items": 
   [
     {
       "item_id": 1, 
       "roduct_Price ": "55.00",  
       "price": "",     
       "product_code": "000002",   
       "quantity": 5
     }
   ]
},
{
  "account_code": "00000",       
  "advance_payment": false,       
  "date": [today's date],
  "order_items": 
   [
     {
       "item_id": 2, 
       "product_Price ": "15.00",  
       "price": "",     
       "product_code": "000003",   
       "quantity": 3
     }
   ]
}

我得到了同一个客户 (account_code) 的多个 JSON 对象,而不是一个带有项目列表的 JSON 对象。

我使用 ADO.NET 从数据库中获取此数据,并使用 SqlDataReader 读取此数据。在 SqlDataReader 中,我创建了一个新对象并在其中填充了有关我的订单的详细信息。一切正常,但问题是 order_items 它应该是订单中所有项目的列表。我想要一个包含多个项目的订单,而不是每个项目的不同订单。 使用下面的代码我可以从我的数据库中获取数据,但我不知道如何将 order_items 按照它们应该在的顺序进行分组。

List<OrderModel> orderList = new List<OrderModel>();
using (SqlDataReader rdr = await cmd.ExecuteReaderAsync())
                    {
                        while (rdr.Read())
                        {
                            OrderModel order = new OrderModel()
                            {
                                Account_code = rdr[0].ToString(),
                                Advance_payment = false,
                                Date = DateTime.Now.Date,
                                Order_Items = new List<Order_items>()
                                    {
                                     //Here is where I should do something instead of creating new
                                     //Order_items, but I don't know what
                                        new Order_items()
                                        {
                                            Order_Item_Rebate = rdr[1].ToString(),
                                            Product_Price = rdr[2].ToString(),
                                            Product_Code = rdr[3].ToString(),
                                            Quantity = rdr[4].ToString()
                                        }
                                    }

                            };
                            orderList.Add(order);
                        }
                        var jsonString = JsonConvert.SerializeObject(orderList);
                        return jsonString;
                    }

我的 OrderModel class 看起来像这样:

public class OrderModel
    {
        public string Account_code { get; set; } 
        public bool Advance_payment { get; set; } 
        public DateTime Date { get; set; }
        public List<Order_items> Order_Items { get; set; } 
    }

    public class Order_items
    {
        public string Order_Item_Rebate { get; set; } 
        public string Product_Price { get; set; } 
        public string Product_Code { get; set; }
        public string Quantity { get; set; }
    }
  

我的数据库中的 table 如下所示:

Account_code Order_Item_Rebate Product_Price Product_Code Quantity
00000 10 105 000001 1
00000 5 55 000002 5
00000 15 15 000002 3

我见过类似的问题,人们建议使用一系列词典,但我不确定我是否理解它们会有什么帮助。我是新手,如果问题不是很聪明,我很抱歉。

  1. while 循环之外定义您的 order 变量。
var order = new OrderModel()
{
    Account_code = rdr[0].ToString(),
    Advance_payment = false,
    Date = DateTime.Now.Date,
    Order_Items = new List<Order_items>()
};        
  1. while 循环中解析订单项
using (SqlDataReader rdr = await cmd.ExecuteReaderAsync())
{
    while (rdr.Read())
    {
        var item = new Order_items()
        {
            Order_Item_Rebate = rdr[1].ToString(),
            Product_Price = rdr[2].ToString(),
            Product_Code = rdr[3].ToString(),
            Quantity = rdr[4].ToString()
        };
        order.Order_Items.Add(item);
    }
}
  1. 序列化循环后唯一的OrderModel
var jsonString = JsonConvert.SerializeObject(order);
return jsonString;

SQL查询会得到“扁平化”的数据,所以需要自己分组。沿着这条线:

var orderDict = new Dictionary<string, OrderModel>(); // mapping from account code to order object
while (rdr.Read())
{
   var accCode = rdr[0].ToString();
   
   // if no object previously added - add a new one 
   if(!orderDict.TryGetValue(accCode, out var order))
   {
       order = new OrderModel()
       {
           Account_code = accCode ,
           Advance_payment = false,
           Date = DateTime.Now.Date,
           Order_Items = new List<Order_items>()
       };
       orderDict[accCode] = order;
   }

   // add details from current result line to order 
   order.Order_Items.Add(new Order_items() {...});
}

var jsonString = JsonConvert.SerializeObject(orderDict.Values); // serialize only values, not the whole dictionary

因此,问题在于您在 while (rdr.Read()) 循环的每次迭代中都创建了一个新的 OrderModel。最直接的方法是根据 Account_code 简单地检查 orderList 中的现有 OrderModel,并仅在以下情况下创建 OrderModel 的新实例找不到一个。例如...

List<OrderModel> orderList = new List<OrderModel>();
using (SqlDataReader rdr = await cmd.ExecuteReaderAsync())
{
    while (rdr.Read())
    {
        // Check to see if there is already an instance of OrderModel with the
        // account code in the list.
        OrderModel order = orderList.FirstOrDefault(om => om.Account_code == rdr[0].ToString());
        if (order == null)
        {
            // If there isn't create a new instance of OrderModel and add it to
            // the list.
            order = new OrderModel
            {
                Account_code = rdr[0].ToString(),
                Advance_payment = false,
                Date = DateTime.Now.Date,
                Order_Items = new List<Order_items>()
            };
            orderList.Add(order);
        }
        
        // Now, just add the new item to Order_Items.
        order.Order_Items.Add(new Order_item
        {
            Order_Item_Rebate = rdr[1].ToString(),
            Product_Price = rdr[2].ToString(),
            Product_Code = rdr[3].ToString(),
            Quantity = rdr[4].ToString()
        });
    }
    var jsonString = JsonConvert.SerializeObject(orderList);
    return jsonString;
}

性能可能很差,尤其是当 orderList 变大时,因为您在 while 循环的每次迭代中迭代一次 orderList。但是,这种基本方法应该有效。不是在 while 循环的每次迭代中创建一个 OrderModel,而是需要确保只在结果集中的每个 Account_code 上创建。

如果您可以控制查询本身,则可以按 Account_code 对结果进行排序以解决性能问题。

List<OrderModel> orderList = new List<OrderModel>();
using (SqlDataReader rdr = await cmd.ExecuteReaderAsync())
{
    OrderModel order = null;
    while (rdr.Read())
    {
        if (order == null || order.Account_code != rdr[0].ToString())
        {
            // The order is null, meaning that this is the first order model to be processed.
            // Or, the order's account code is different than the current account code on the result set, meaning we have begun processing a new order.
            // In either case, you need to add a new order to the list so
            // you can start filling in its items.
            order = new OrderModel
            {
                Account_code = rdr[0].ToString(),
                Advance_payment = false,
                Date = DateTime.Now.Date,
                Order_Items = new List<Order_items>()
            };
            orderList.Add(order);
        }        
        
        // Now, just add the new item to Order_Items.
        order.Order_Items.Add(new Order_item
        {
            Order_Item_Rebate = rdr[1].ToString(),
            Product_Price = rdr[2].ToString(),
            Product_Code = rdr[3].ToString(),
            Quantity = rdr[4].ToString()
        });
    }
    var jsonString = JsonConvert.SerializeObject(orderList);
    return jsonString;
}

上述方法只有在您可以按帐户代码对查询结果进行排序时才有效。