简体   繁体   中英

Flattened records to parent/child objects using LINQ. Without duplication of data

I am trying to better understand grouping using LINQ. I would like to take a collection of flattened records and convert them into two object collections in a parent/child relationship. In my example the flattened records are contained in ImportedExpenses class while the Expense/ExpenseLineItem classes form the parent/child relationship respectively.

public class ImportedExpense {
    public string EmployeeName {get; set;}
    public string CustomerName {get; set;}
    public DateTime ExpenseDate {get; set;}
    public Decimal Amount {get; set;}
    public string Description {get; set;}
}

public class Expense {
    public string EmployeeName {get; set;}
    public string CustomerName {get; set;}
    public List<ExpenseLineItem> LineItems {get; set;}
}

public class ExpenseLineItem {
    public DateTime ExpenseDate {get; set;}
    public Decimal Amount {get; set;}
    public string Description {get; set;}
}

In the past I have accomplished this by repeating information in the ExpenseLineItem class.

public class ExpenseLineItem {
    public string EmployeeName {get; set;}
    public string CustomerName {get; set;}
    public DateTime ExpenseDate {get; set;}
    public Decimal Amount {get; set;}
    public string Description {get; set;}
}

and I would use the following LINQ statement where importedData is a collection of type ImportedExpense

var expenseCollection = importedData.GroupBy(x => 
    new 
    {
        x.EmployeeName,
        x.CustomerName
    })
    .Select (y => new Expense()
    {
        EmployeeName = y.Key.EmployeeName,
        CustomerName = y.Key.CustomerName,
        LineItems = y.ToList();
    });

However, I would like to accomplish the same thing without having to repeat information in the Expense and ExpenseItem class.

How would I form the LINQ query to accomplish this? If possible with the fluent syntax as I am more familiar with it vs the query syntax.

I am not sure I have understood your question right, but if you want to transform ImportedExpense to an hierarchy of Expense->ExpenseLineItem , you are almost there with your code. Try this:

var expenseCollection = importedData.GroupBy(x => 
    new 
    {
        x.EmployeeName,
        x.CustomerName
    })
    .Select (y => new Expense()
    {
        EmployeeName = y.Key.EmployeeName,
        CustomerName = y.Key.CustomerName,
        LineItems = y.Select(ie => new ExpenseLineItem()
        {
            ExpenseDate = ie.ExpenseDate,
            Amount = ie.Amount,
            Description = ie.Description
        }).ToList();
    });

There is a GroupBy extension that lets you do a projection of the grouped items. You can use this to project ExpenseLineItem s grouped by the anonymous type with the other data points in it.

In code it looks like this:

var expenseCollection = importedData
    .GroupBy
    (
        x => new { x.EmployeeName, x.CustomerName },
        x => new ExpenseLineItem
        {
            ExpenseDate = x.ExpenseDate,
            Amount = x.Amount,
            Description = x.Description
        }
    )
    .Select
    (
        y => new Expense
        {
            EmployeeName = y.Key.EmployeeName,
            CustomerName = y.Key.CustomerName,
            LineItems = y.ToList()
        }
    );

Alternatively you can do the projection in the select:

var expenseCollection = importedData
    .GroupBy(x => new { x.EmployeeName, x.CustomerName })
    .Select
    (
        y => new Expense
        {
            EmployeeName = y.Key.EmployeeName,
            CustomerName = y.Key.CustomerName,
            LineItems = y.Select
            (
                item => new ExpenseLineItem
                {
                    ExpenseDate = item.ExpenseDate,
                    Amount = item.Amount,
                    Description = item.Description
                }
            ).ToList()
        }
    );

You could move the projection out to a separate method or a cast operator, but I think the above is nicely transparent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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