using System;
using System.Collections.Generic;
using System.Linq;
namespace TestApp
{
class Program
{
public class Order
{
public Order()
{
Items = new List<OrderItem>();
}
public string Code { get; set; }
public ICollection<OrderItem> Items { get; set; }
}
public class OrderItem
{
public OrderItem()
{
SubItems = new List<SubItem>();
}
public decimal Quantity { get; set; }
public decimal Price { get; set; }
public ICollection<SubItem> SubItems { get; set; }
}
public class SubItem
{
public DateTime Date { get; set; }
public decimal Quantity { get; set; }
public string UserName { get; set; }
}
static void Main(string[] args)
{
Order order = new Order();
order.Code = "123";
order.Items.Add(new OrderItem()
{
Price = 30,
Quantity = 3,
SubItems = new List<SubItem>()
{
new SubItem() { Date = DateTime.Now, Quantity = 1, UserName = "User1" },
new SubItem() { Date = DateTime.Now, Quantity = 2, UserName = "User2" }
}
});
order.Items.Add(new OrderItem()
{
Price = 500,
Quantity = 50,
SubItems = new List<SubItem>()
{
new SubItem() { Date = DateTime.Now, Quantity = 20, UserName = "User1" },
new SubItem() { Date = DateTime.Now, Quantity = 20, UserName = "User2" },
new SubItem() { Date = DateTime.Now, Quantity = 10, UserName = "User3" }
}
});
order.Items.Add(new OrderItem()
{
Price = 1000,
Quantity = 50,
SubItems = new List<SubItem>()
});
var res = order.Items
.SelectMany(i => i.SubItems.DefaultIfEmpty(), (Item, Sub) => new { Item, Sub })
.Select(r => new { order.Code, r.Item.Price, ItemQuantity = r.Item.Quantity, SubItemQuantity = r.Sub == null ? null : (Decimal?) r.Sub.Quantity ,UserName = r.Sub == null ? (string)null : r.Sub.UserName });
foreach(var x in res)
{
System.Console.WriteLine(x.ToString());
}
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLkxpbnE7CgpuYW1lc3BhY2UgVGVzdEFwcAp7CgogICAgY2xhc3MgUHJvZ3JhbQogICAgewogICAgICAgIHB1YmxpYyBjbGFzcyBPcmRlcgogICAgICAgIHsKICAgICAgICAgICAgcHVibGljIE9yZGVyKCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgSXRlbXMgPSBuZXcgTGlzdDxPcmRlckl0ZW0+KCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHB1YmxpYyBzdHJpbmcgQ29kZSB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBJQ29sbGVjdGlvbjxPcmRlckl0ZW0+IEl0ZW1zIHsgZ2V0OyBzZXQ7IH0KICAgICAgICB9CgogICAgICAgIHB1YmxpYyBjbGFzcyBPcmRlckl0ZW0KICAgICAgICB7CiAgICAgICAgICAgIHB1YmxpYyBPcmRlckl0ZW0oKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBTdWJJdGVtcyA9IG5ldyBMaXN0PFN1Ykl0ZW0+KCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHB1YmxpYyBkZWNpbWFsIFF1YW50aXR5IHsgZ2V0OyBzZXQ7IH0KICAgICAgICAgICAgcHVibGljIGRlY2ltYWwgUHJpY2UgeyBnZXQ7IHNldDsgfQogICAgICAgICAgICBwdWJsaWMgSUNvbGxlY3Rpb248U3ViSXRlbT4gU3ViSXRlbXMgeyBnZXQ7IHNldDsgfQogICAgICAgIH0KCiAgICAgICAgcHVibGljIGNsYXNzIFN1Ykl0ZW0KICAgICAgICB7CiAgICAgICAgICAgIHB1YmxpYyBEYXRlVGltZSBEYXRlIHsgZ2V0OyBzZXQ7IH0KICAgICAgICAgICAgcHVibGljIGRlY2ltYWwgUXVhbnRpdHkgeyBnZXQ7IHNldDsgfQogICAgICAgICAgICBwdWJsaWMgc3RyaW5nIFVzZXJOYW1lIHsgZ2V0OyBzZXQ7IH0KICAgICAgICB9CgogICAgICAgIHN0YXRpYyB2b2lkIE1haW4oc3RyaW5nW10gYXJncykKICAgICAgICB7CiAgICAgICAgICAgIE9yZGVyIG9yZGVyID0gbmV3IE9yZGVyKCk7CiAgICAgICAgICAgIG9yZGVyLkNvZGUgPSAiMTIzIjsKICAgICAgICAgICAgb3JkZXIuSXRlbXMuQWRkKG5ldyBPcmRlckl0ZW0oKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBQcmljZSA9IDMwLAogICAgICAgICAgICAgICAgUXVhbnRpdHkgPSAzLAogICAgICAgICAgICAgICAgU3ViSXRlbXMgPSBuZXcgTGlzdDxTdWJJdGVtPigpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFN1Ykl0ZW0oKSB7IERhdGUgPSBEYXRlVGltZS5Ob3csIFF1YW50aXR5ID0gMSwgVXNlck5hbWUgPSAiVXNlcjEiIH0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBTdWJJdGVtKCkgeyBEYXRlID0gRGF0ZVRpbWUuTm93LCBRdWFudGl0eSA9IDIsIFVzZXJOYW1lID0gIlVzZXIyIiB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pOwoKCiAgICAgICAgICAgIG9yZGVyLkl0ZW1zLkFkZChuZXcgT3JkZXJJdGVtKCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgUHJpY2UgPSA1MDAsCiAgICAgICAgICAgICAgICBRdWFudGl0eSA9IDUwLAogICAgICAgICAgICAgICAgU3ViSXRlbXMgPSBuZXcgTGlzdDxTdWJJdGVtPigpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFN1Ykl0ZW0oKSB7IERhdGUgPSBEYXRlVGltZS5Ob3csIFF1YW50aXR5ID0gMjAsIFVzZXJOYW1lID0gIlVzZXIxIiB9LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgU3ViSXRlbSgpIHsgRGF0ZSA9IERhdGVUaW1lLk5vdywgUXVhbnRpdHkgPSAyMCwgVXNlck5hbWUgPSAiVXNlcjIiIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFN1Ykl0ZW0oKSB7IERhdGUgPSBEYXRlVGltZS5Ob3csIFF1YW50aXR5ID0gMTAsIFVzZXJOYW1lID0gIlVzZXIzIiB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pOwoKCiAgICAgICAgICAgIG9yZGVyLkl0ZW1zLkFkZChuZXcgT3JkZXJJdGVtKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByaWNlID0gMTAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUXVhbnRpdHkgPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3ViSXRlbXMgPSBuZXcgTGlzdDxTdWJJdGVtPigpCiAgICAgICAgICAgIH0pOwoKCiAgICAgICAgICAgIHZhciByZXMgPSBvcmRlci5JdGVtcwogICAgICAgICAgICAgICAgICAgICAgICAgICAuU2VsZWN0TWFueShpID0+IGkuU3ViSXRlbXMuRGVmYXVsdElmRW1wdHkoKSwgKEl0ZW0sIFN1YikgPT4gbmV3IHsgSXRlbSwgU3ViIH0pCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC5TZWxlY3QociA9PiBuZXcgeyBvcmRlci5Db2RlLCByLkl0ZW0uUHJpY2UsIEl0ZW1RdWFudGl0eSA9IHIuSXRlbS5RdWFudGl0eSwgU3ViSXRlbVF1YW50aXR5ID0gci5TdWIgPT0gbnVsbCA/IG51bGwgOiAoRGVjaW1hbD8pIHIuU3ViLlF1YW50aXR5ICxVc2VyTmFtZSA9IHIuU3ViID09IG51bGwgPyAoc3RyaW5nKW51bGwgOiByLlN1Yi5Vc2VyTmFtZSB9KTsKCiAgICAgICAgICAgIGZvcmVhY2godmFyIHggaW4gcmVzKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBTeXN0ZW0uQ29uc29sZS5Xcml0ZUxpbmUoeC5Ub1N0cmluZygpKTsKICAgICAgICAgICAgfQogICAgICAgIH0KfQp9
{ Code = 123, Price = 30, ItemQuantity = 3, SubItemQuantity = 1, UserName = User1 }
{ Code = 123, Price = 30, ItemQuantity = 3, SubItemQuantity = 2, UserName = User2 }
{ Code = 123, Price = 500, ItemQuantity = 50, SubItemQuantity = 20, UserName = User1 }
{ Code = 123, Price = 500, ItemQuantity = 50, SubItemQuantity = 20, UserName = User2 }
{ Code = 123, Price = 500, ItemQuantity = 50, SubItemQuantity = 10, UserName = User3 }
{ Code = 123, Price = 1000, ItemQuantity = 50, SubItemQuantity = , UserName = }