Search code examples
c#entity-frameworklinqlambda

How can I get data for parent list which can have it's child/nested list's empty while flattening using SelectMany in C#


I'm trying to flatten a List using SelectMany() method, the problem is the child/nested lists can have data or sometimes it can be empty. I want the lambda query to at least return the data of parent list i.e. InventoryCode & InventoryDescription, because the parent collection can never be empty. I tried below query, but result count is 0 when any of the child/nested lists are empty.

public class Share
{
   public string shareCode {get;set;}
   public int shareNumber  {get;set;}
}
public class ProductModel
{
   public string productCode {get;set;}
   public string productName{get;set;}
   public List<Share> share{get;set;}
}

public class InventoryModel
{
   public string inventoryCode {get;set;}
   public string inventoryDescription {get;set;}
   public List<Product> products {get;set;}
}

Note-InventoryModel is also used as list in some other model

The below code which I have written work's well when child list's are not empty, but it fails to return any data when any of the child list's is empty

var invenFlatList = lstInventory.SelectMany(x => x.products.SelectMany(y => y.shares.Select(z => new NewModel
            {
                inventoryCode = x.inventoryCode ,
                inventoryDescription = x.inventoryDescription ,
                productCode = y.productCode ,
                productName= y.productName,
                shareCode = z.shareCode ,
                shareNumber  = z.shareNumber  
            }))).ToList();

Solution

  • You can use following approach using DefaultIfEmpty with a fallback item:

    List<NewModel> resultList = lstInventory
            .SelectMany(inv => inv.products
                .SelectMany(prod => prod.shares
                    .Select(share => new NewModel
                    {
                        inventoryCode = inv.inventoryCode,
                        inventoryDescription = inv.inventoryDescription,
                        productCode = prod.productCode,
                        productName = prod.productName,
                        shareCode = share.shareCode,
                        shareNumber = share.shareNumber
                    })
                  .DefaultIfEmpty(new NewModel
                  {
                      inventoryCode = inv.inventoryCode,
                      inventoryDescription = inv.inventoryDescription,
                      productCode = prod.productCode,
                      productName = prod.productName,
                      shareCode = null,
                      shareNumber = 0
                  })))
            .ToList();