【问题标题】:How to yield multiple objects with respect to a multi-valued column in Dynamic Linq如何针对 Dynamic Linq 中的多值列生成多个对象
【发布时间】:2019-01-29 08:47:40
【问题描述】:

场景: 我必须导出一个包含零件列表的 excel 文件。我们使用户能够选择列并在导出的文件中仅获取选定列的数据。由于这是一个动态报告,我没有使用任何具体的类来映射报告,因为这将导致在报告中导出空列标题,这是不必要的。我正在使用 Dynamic Linq 来处理这种情况。

我有一个从动态 linq 获取的动态对象列表。

[
    {"CleanPartNo":"Test","Description":"test","AliasPartNo":["258","145","2313","12322"]},
    {"CleanPartNo":"Test1","Description":"test1","AliasPartNo":[]}
]

我怎样才能从这个 json 中得到 4 行,比如

请注意,我不能使用强类型对象来反序列化/使用 JSON.Net 映射它

更新 以下是代码:

 public class Part
    {
        public int Id { get; set; }
        public string CleanPartNo { get; set; }
        public string Description { get; set; }
        public List<PartAlias> AliasPartNo { get; set; }
    }

public class PartAlias
    {
        public int PartId { get; set; }
        public int PartAliasId { get; set; }
        public string AliasPartNo { get; set; }
    }




var aliases = new List<PartAlias> {
                new PartAlias{AliasPartNo="258" },
                new PartAlias{AliasPartNo="145" },
                new PartAlias{AliasPartNo="2313" },
                new PartAlias{AliasPartNo="12322" }
            };
List<Part> results = new List<Part> {
                new Part{CleanPartNo="Test", Description= "test", PartAlias=aliases  },
                new Part{CleanPartNo="Test1", Description= "test1" }

            };

var filters = "CleanPartNo,Description, PartAlias.Select(AliasPartNo) as AliasPartNo";
var dynamicObject = JsonConvert.SerializeObject(results.AsQueryable().Select($"new ({filters})"));

在dynamicObject变量中我得到了上面提到的json

【问题讨论】:

  • 您能提供一个minimal reproducible example吗?具体来说,如何设置此代码以在控制台应用程序中运行它?
  • 我已经更新了代码,请检查
  • 我们能知道作为数组的列的名称吗?这将使这 2 班轮

标签: c# json linq json.net dynamic-linq


【解决方案1】:

免责声明:以下依赖于匿名类,这与动态 LINQ 不完全相同(根本不),但我认为它可能会有所帮助,具体取决于您的需要,因此我决定贴出来。

要扁平化您的列表,您可以使用嵌套的 Select,然后是 SelectMany免责声明:这假定每个部分至少有一个别名,请参阅下面的完整信息代码)

var flattenedResult = result.Select(part => part.AliasPartNumber.Select(alias => new 
                                                                                 { 
                                                                                     CleanPartNo = part.CleanPartNo, 
                                                                                     Description = part.Description,
                                                                                     AliasPartNo = alias.AliasPartNo
                                                                                 })
                            .SelectMany(part => part);

您首先从result(外部Select)投射您的项目。投影将每个项目投影到匿名类型的IEnumerable,其中每个项目对应一个别名部件号。由于外部Select 将产生IEnumerable&lt;IEnumerable&gt;(或类似的东西),我们使用SelectMany 从嵌套IEnumerables 中获取所有项目中的单个IEnumerable。您现在可以使用 JsonConvert 序列化匿名类实例的 IEnumerable

var json = sonConvert.SerializeObject(flatResults);

处理没有别名的部分

如果没有别名,内部选择将产生一个空的IEnumerable,因此我们将不得不引入一个特殊情况

var selector = (Part part) => part.AliasPartNumber?.Any() == true
                                  ? part.AliasPartNumber.Select(alias => new 
                                                                         { 
                                                                             CleanPartNo = part.CleanPartNo, 
                                                                             Description = part.Description,
                                                                             AliasPartNo = alias.AliasPartNo
                                                                         })
                                  : new[]
                                    {
                                        new 
                                        { 
                                            CleanPartNo = part.CleanPartNo, 
                                            Description = part.Description,
                                            AliasPartNo = alias.AliasPartNo
                                        }
                                    };
var flattenedResult = result.Select(selector).SelectMany(item => item);

【讨论】:

  • 这个答案不知何故给了我一些想法,但它不是我真正想要的。我不能使用具体类型。
  • @AliHasan 那么也许您可以在问题中提供更多背景信息。这可能有助于提供有用的答案。
【解决方案2】:

从您提供的 json 中,您可以通过这种方式获取按名称分组的值:

var array = JArray.Parse(json);
var lookup = array.SelectMany(x => x.Children<JProperty>()).ToLookup(x => x.Name, x => x.Value);

那么这只是一种简单的循环查找方式以填充 excel 列。

但是,我建议在 JSON 之前进行扁平化。即使不知道数组列的名称,我也尝试了一段时间来实现它,但我失败了,因为这是你的工作,我不会再尝试了:P

我认为这里最好的方法是实现自定义转换器,该转换器只会为数组属性乘以对象。如果你做得好,你将完全免费获得无限关卡。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 2020-05-27
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 2019-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多