如何使用Linq to SQL在C#中将普通对象转换为嵌套子对象

huangapple go评论61阅读模式
英文:

How to convert plain object to nested sub object using Linq to SQL C#

问题

我理解你的问题,你想将从数据库中获取的数据绑定到Root模型,以生成JSON格式的数据。以下是可能的解决方案:

string connectionString = "data source=localhost;initial catalog=ASPENDV;integrated security=true;";
var result = new List<DataClass>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
    result = connection.Query<DataClass>("sp_TestData", commandType: System.Data.CommandType.StoredProcedure).ToList();
}

var groupedData = result.GroupBy(x => x.LocationId).Select(group =>
{
    var location = group.First(); // Assuming Location data is the same within a group
    return new Location
    {
        LocationID = location.LocationId,
        DBSIdentifier = location.DBSIdentifier,
        DBSVersion = location.DBSVersion.ToString(), // Convert int to string
        InterfaceVersion = location.InterfaceVersion,
        LanguageCode = location.LanguageCode,
        CounterSale = group.GroupBy(x => x.InvoiceNumber).Select(counterSaleGroup =>
        {
            var counterSale = counterSaleGroup.First(); // Assuming CounterSale data is the same within a group
            return new CounterSale
            {
                InvoiceNumber = counterSale.InvoiceNumber,
                CreationTimestamp = counterSale.CreationTimestamp,
                Part = counterSaleGroup.Select(partData =>
                {
                    return new Part
                    {
                        PartNumber = partData.PartNumber,
                        Quantity = partData.Quantity,
                        Description = partData.Description
                    };
                }).ToList()
            };
        }).ToList()
    };
}).ToList();

var root = new Root
{
    Location = groupedData.ToList()
};

此代码首先从数据库获取数据,并将其分组。然后,它将数据映射到Root模型,以生成所需的JSON格式。请注意,这里假设了一些数据的唯一性和一致性,你可能需要根据实际情况进行适当的调整。

英文:

I am working an application where I am receiving a plain list from database which I need to convert into the following JSON object. Here is what I have tried so far. I am not willing use nested foreach loops.

> JSON

{
  &quot;Location&quot;: [
    {
      &quot;LocationID&quot;: &quot;123456&quot;,
      &quot;DBSIdentifier&quot;: &quot;EQUIP&quot;,
      &quot;DBSVersion&quot;: &quot;3221&quot;,
      &quot;InterfaceVersion&quot;: &quot;2.0&quot;,
      &quot;LanguageCode&quot;: &quot;EN&quot;,
      &quot;CounterSale&quot;: [
        {
          &quot;InvoiceNumber&quot;: &quot;941041&quot;,
          &quot;CreationTimestamp&quot;: &quot;2018-04-02T07:03:18&quot;,
          &quot;InvoiceTimestamp&quot;: &quot;2018-04-02T07:03:18&quot;,
          &quot;Part&quot;: [
            {
              &quot;PartNumber&quot;: &quot;AT194969&quot;,
              &quot;Quantity&quot;: &quot;1.00&quot;,
              &quot;Description&quot;: &quot;KEY&quot;,
              &quot;DeerePart&quot;: &quot;true&quot;,
              &quot;MiscellaneousPart&quot;: &quot;false&quot;,
              &quot;PartsPerPackage&quot;: &quot;1&quot;,
              &quot;StockingLogicCode&quot;: &quot;12A&quot;,
              &quot;UnitofMeasure&quot;: &quot;&quot;,
              &quot;Warehouse&quot;: &quot;D-1&quot;,
              &quot;HistorySale&quot;: &quot;N&quot;,
              &quot;OnlineOrder&quot;: &quot;&quot;,
              &quot;PickListID&quot;: &quot;&quot;
            }
          ]
        }]
		}]
	}

> CODE

string connectionString = &quot;data source=localhost;initial catalog=ASPENDV;integrated security=true;&quot;;
var result = new List&lt;DataClass&gt;();
using (SqlConnection connection = new SqlConnection(connectionString))
{
    result = connection.Query&lt;DataClass&gt;(&quot;sp_TestData&quot;, commandType: System.Data.CommandType.StoredProcedure).ToList();
}


#region [@ ##### ]


var obj = result.GroupBy(x =&gt; x.LocationId);

var root = obj.Select(x =&gt; new Root()
{
    Location = x.Select(l =&gt; new Location()
    {
        LocationID = l.LocationId,
        DBSIdentifier = l.DBSIdentifier,
        CounterSale = x.GroupBy(x =&gt; x.InvoiceNumber).Select(c =&gt; new CounterSale()
        {
            InvoiceNumber = l.InvoiceNumber,
            CreationTimestamp = l.CreationTimestamp,
            Part = x.Select(p =&gt; new Part()
            {
                PartNumber = p.PartNumber,
                Description = p.Description,
            }).ToList()
        }).ToList(),
    }).ToList(),
}); ;

#endregion

> MODELS

   public class DataClass
        {
            public string? LanguageCode { get; set; }
            public DateTime CreationTimestamp { get; set; }
            public string? DBSHEADERPARTSK { get; set; }
            public string? DBSIdentifier { get; set; }
            public int DBSVersion { get; set; }
            public string? Description { get; set; }
            public string? InvoiceNumber { get; set; }
            public Nullable&lt;DateTime&gt; InvoiceTimestamp { get; set; }
            public string? PartNumber { get; set; }
            public string? PartSerialNumber { get; set; }
            public int? PartPerPackage { get; set; }
            public int MfgId { get; set; }
            public int LocationId { get; set; }
        }

    public class CounterSale
    {
        public CounterSale()
        {
            this.Part = new List&lt;Part&gt;();
        }
        public string? InvoiceNumber { get; set; }
        public DateTime CreationTimestamp { get; set; }
        public DateTime InvoiceTimestamp { get; set; }
        public List&lt;Part&gt; Part { get; set; }
    }

    public class Location
    {
        public Location()
        {
            this.CounterSale = new List&lt;CounterSale&gt;();
        }
        public int LocationID { get; set; }
        public string? DBSIdentifier { get; set; }
        public string? DBSVersion { get; set; }
        public string? InterfaceVersion { get; set; }
        public string? LanguageCode { get; set; }
        public List&lt;CounterSale&gt; CounterSale { get; set; }
    }

    public class Part
    {
        public string? PartNumber { get; set; }
        public string? Quantity { get; set; }
        public string? Description { get; set; }
    }

    public class Root
    {
        public Root()
        {
            this.Location = new List&lt;Location&gt;();
        }
        public List&lt;Location&gt; Location { get; set; }
    }

My stored procedure returns data which I am binding into DataClass which I need to bind into Root Model as like JSON.

I am not able to bind the result into Root Model how can I do that ?

答案1

得分: 0

我建议从底部开始构建嵌套分组,首先按位置和发票分组,然后再次按位置分组。生成的结构将类似于您期望的结构,然后只需遍历这些分组以构建最终的嵌套数据结构。

// 代码部分不要翻译
List<DataClass> result;
using (SqlConnection connection = new SqlConnection(connectionString))
{
    result = connection.Query<DataClass>("sp_TestData", commandType: System.Data.CommandType.StoredProcedure).ToList();
}

// Grouping<Key=LocationId, Collection=Grouping<Key={LocationId, InvoiceNumber}, Collection=DataClass>
var nestedGroups = result
    .GroupBy(dat => new {dat.LocationId, dat.InvoiceNumber})
    .GroupBy(invGroup => invGroup.Key.LocationId);

var root = new Root()
{
    Location = nestedGroups.Select(locGroup => new Location()
    {
        LocationID = locGroup.Key,
        DBSIdentifier = locGroup.First().First().DBSIdentifier,
        CounterSale = locGroup.Select(invGroup => new CounterSale()
        {
            InvoiceNumber = invGroup.Key.InvoiceNumber,
            CreationTimestamp = invGroup.First().CreationTimestamp,
            Part = invGroup.Select(dat => new Part()
            {
                PartNumber = dat.PartNumber,
                Description = dat.Description,
            }).ToList()
        }).ToList()
    }).ToList()
};

.First().First().First() 的调用用于深入到最低级以检索未包含在上层分组键中的值。您可以在 .GroupBy(...) 选择器中包含 DBSIdentifierCreationTimestamp,但与仅使用 ID 进行分组相比,这可能效率较低。

查看此 .NET fiddle 进行演示。

示例结果已经提供。

英文:

I suggest building a nested grouping from the bottom up by first grouping by location & invoice and then grouping again just by location. The resulting structure will similar to your desired structure, and it is then just a matter of traversing the groupings to build out your final nested data structure.

Something like:

List&lt;DataClass&gt; result; // No initialization needed here
using (SqlConnection connection = new SqlConnection(connectionString))
{
    result = connection.Query&lt;DataClass&gt;(&quot;sp_TestData&quot;, commandType: System.Data.CommandType.StoredProcedure).ToList();
}

// Grouping&lt;Key=LocationId, Collection=Grouping&lt;Key={LocationId, InvoiceNumber}, Collection=DataClass&gt;
var nestedGroups = result
	.GroupBy(dat =&gt; new {dat.LocationId, dat.InvoiceNumber})
	.GroupBy(invGroup =&gt; invGroup.Key.LocationId)
	//??maybe?? .ToList()
	;

var root = new Root()
{
    Location = nestedGroups.Select(locGroup =&gt; new Location()
    {
        LocationID = locGroup.Key,
        DBSIdentifier = locGroup.First().First().DBSIdentifier,
        CounterSale = locGroup.Select(invGroup =&gt; new CounterSale()
        {
            InvoiceNumber = invGroup.Key.InvoiceNumber,
            CreationTimestamp = invGroup.First().CreationTimestamp,
            Part = invGroup.Select(dat =&gt; new Part()
            {
                PartNumber = dat.PartNumber,
                Description = dat.Description,
            }).ToList()
        }).ToList()
    }).ToList()
};

The .First() and .First().First() calls are used to reach down into the lowest level to retrieve values not included in the upper level grouping key. You could include DBSIdentifier and CreationTimestamp in the .GroupBy(...) selectors, but that would likely be less efficient than grouping using just the IDs.

See this .NET fiddle for a demo.

Sample results:

{
  &quot;Location&quot;: [
    {
      &quot;LocationID&quot;: 1,
      &quot;DBSIdentifier&quot;: &quot;11&quot;,
      &quot;DBSVersion&quot;: null,
      &quot;InterfaceVersion&quot;: null,
      &quot;LanguageCode&quot;: null,
      &quot;CounterSale&quot;: [
        {
          &quot;InvoiceNumber&quot;: &quot;201&quot;,
          &quot;CreationTimestamp&quot;: &quot;2023-05-11T03:18:33.9510984+00:00&quot;,
          &quot;InvoiceTimestamp&quot;: &quot;0001-01-01T00:00:00&quot;,
          &quot;Part&quot;: [
            {
              &quot;PartNumber&quot;: &quot;301&quot;,
              &quot;Quantity&quot;: null,
              &quot;Description&quot;: &quot;A&quot;
            },
            {
              &quot;PartNumber&quot;: &quot;302&quot;,
              &quot;Quantity&quot;: null,
              &quot;Description&quot;: &quot;B&quot;
            }
          ]
        },
        {
          &quot;InvoiceNumber&quot;: &quot;202&quot;,
          &quot;CreationTimestamp&quot;: &quot;2023-05-11T03:18:33.9510984+00:00&quot;,
          &quot;InvoiceTimestamp&quot;: &quot;0001-01-01T00:00:00&quot;,
          &quot;Part&quot;: [
            {
              &quot;PartNumber&quot;: &quot;303&quot;,
              &quot;Quantity&quot;: null,
              &quot;Description&quot;: &quot;C&quot;
            }
          ]
        }
      ]
    },
    {
      &quot;LocationID&quot;: 2,
      &quot;DBSIdentifier&quot;: &quot;22&quot;,
      &quot;DBSVersion&quot;: null,
      &quot;InterfaceVersion&quot;: null,
      &quot;LanguageCode&quot;: null,
      &quot;CounterSale&quot;: [
        {
          &quot;InvoiceNumber&quot;: &quot;203&quot;,
          &quot;CreationTimestamp&quot;: &quot;2023-05-11T03:18:33.9510984+00:00&quot;,
          &quot;InvoiceTimestamp&quot;: &quot;0001-01-01T00:00:00&quot;,
          &quot;Part&quot;: [
            {
              &quot;PartNumber&quot;: &quot;301&quot;,
              &quot;Quantity&quot;: null,
              &quot;Description&quot;: &quot;A&quot;
            }
          ]
        }
      ]
    }
  ]
}

huangapple
  • 本文由 发表于 2023年5月11日 04:45:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76222437.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定