简体   繁体   English

使用LINQ将一行变成两个对象吗?

[英]Turn one row into two objects using LINQ?

I have a single item array that I compare to an updated item array to determine the distinct list of changed columns. 我有一个项目数组,可以将它与更新的项目数组进行比较,以确定更改列的不同列表。 It's working. 工作正常

But I need to build two objects out of that one row because I need to send two objects to the API I'm using to send the email. 但是我需要在那一行中构建两个对象,因为我需要向我用来发送电子邮件的API发送两个对象。 One for the old value and one for the new value. 一种是旧值,另一种是新值。 I've tried it two different ways: 我尝试了两种不同的方法:

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .Select(r => new AppServices.NotificationData[]
        {
            new AppServices.NotificationData
            {
                Key = string.Format("{0}OldValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(currentRow[r.Index])
            },
            new AppServices.NotificationData
            {
                Key = string.Format("{0}NewValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(updatedRow[r.Index])
            }                        
        });

but this one actually, honestly as expected, gives me an enumerable of arrays. 但实际上,正如预期的那样,这实际上给了我很多数组。 I've also tried it like this: 我也尝试过这样:

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .Select(r => new AppServices.NotificationData
        {
            Key = string.Format("{0}OldValue",
                columns[r.Index].ColumnName.EmailTemplateName(type)),
            Value = Convert.ToString(currentRow[r.Index])
        })
        .Select(r => new AppServices.NotificationData
        {
            Key = string.Format("{0}NewValue",
                columns[r.Index].ColumnName.EmailTemplateName(type)),
            Value = Convert.ToString(updatedRow[r.Index])
        });

but the problem here is that the second Select passes in the NotificationData object from the previous select, so r isn't actually the item array. 但是这里的问题是第二个Select从先前的select中传入NotificationData对象,因此r实际上不是item数组。

Here currentRow and updatedRow are DataRow objects representing the old and new data respectively. 这里currentRowupdatedRow是分别代表旧数据和新数据的DataRow对象。

I'm sure there's a way to get what I'm after, I just don't know how. 我敢肯定有一种方法可以得到我想要的东西,我只是不知道怎么做。

So, how do I get a Select , which is built to return a single type, to return two instances of the same object so that the enumerable is ultimately IEnumerable<NotificationData> ? 因此,如何获取Select ,它可以返回一个类型,返回同一对象的两个实例,以便枚举最终是IEnumerable<NotificationData>

Use SelectMany instead of Select in the first query: 在第一个查询中使用SelectMany代替Select

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .SelectMany(r => new AppServices.NotificationData[]
        {
            new AppServices.NotificationData
            {
                Key = string.Format("{0}OldValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(currentRow[r.Index])
            },
            new AppServices.NotificationData
            {
                Key = string.Format("{0}NewValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(updatedRow[r.Index])
            }                        
        });

It will flatten your IEnumerable<IEnumerable<T>> into IEnumerable<T> . 它将您的IEnumerable<IEnumerable<T>>展平为IEnumerable<T>

If what you want is to have two objects created per row , and then be able to send these two objects together to your API, then I think that the best way would be to use an anonymous type. 如果您想要的是每行创建两个对象 ,然后将这两个对象一起发送到您的API,那么我认为最好的方法是使用匿名类型。

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .Select(r => new {
            NotificationForServiceA = new AppServices.NotificationData({
                Key = string.Format("{0}OldValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(currentRow[r.Index])
            }),
            NotificationForServiceB = new AppServices.NotificationData({
                Key = string.Format("{0}NewValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(updatedRow[r.Index])
            })
        });

Then you could use it that way: 然后,您可以通过以下方式使用它:

var oneItem = updates.FirstOrDefault();
myApi(oneItem.NotificationForServiceA, oneItem.NotificationForServiceB);

If what you want is to create two NotificationData per row and have them merged/flattened in one enumerable then you should use SelectMany to perform that. 如果要在每行创建两个NotificationData并将它们合并/合并为一个可枚举 ,则应使用SelectMany执行该操作。 See MarcinJuraszek answer to do that. 参见MarcinJuraszek的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM