C# linq build table from sub list of list - c#

In result of linq query I want to get List<Record> records that should contain something like this:
Id=1, Number=1,Weight=23,Street="Testing street"
Id=1, Number=1,Weight=23,Street="Testing street"
Id=1, Number=1,Weight=23,Street="Testing street"
Id=1, Number=1,Weight=23,Street="Testing street"
Id=1, Number=1,Weight=23,Street="Testing street"
Id=1, Number=1,Weight=23,Street="Testing street"
Code:
namespace ConsoleApplication24
{
class Program
{
static void Main(string[] args)
{
List<Train> Depos = new List<Train>();
Train train = new Train();
train.Id = 1;
List<Wagon> wagons = new List<Wagon>();
wagons.Add(new Wagon { Number = 1, Weight = 23 });
wagons.Add(new Wagon { Number = 1, Weight = 23 });
wagons.Add(new Wagon { Number = 1, Weight = 23 });
wagons.Add(new Wagon { Number = 1, Weight = 23 });
wagons.Add(new Wagon { Number = 1, Weight = 23 });
wagons.Add(new Wagon { Number = 1, Weight = 23 });
train.Wagons = wagons;
Depos.Add(train);
List<Adress> Adresses = new List<Adress>();
Adress adress = new Adress();
adress.Id = 1;
adress.Street = "Testing street";
Adresses.Add(adress);
List<Record> records = (from dep in Depos join adr in Adresses on dep.Id equals adr.Id select new Record { Id = dep.Id }).ToList();
}
}
public class Record
{
public int Id { get; set; }
public int Weight { get; set; }
public string Street { get; set; }
public int Number { get; set; }
}
public class Train
{
public int Id { get; set; }
public List<Wagon> Wagons { get; set; }
}
public class Wagon
{
public int Weight { get; set; }
public int Number { get; set; }
}
public class Adress
{
public int Id { get; set; }
public string Street { get; set; }
}
}
What is the best way to do this?

You need to use SelectMany, or, in query syntax, a second from, to flatten your list of lists:
List<Record> records =(from dep in Depos
join adr in Adresses on dep.Id equals adr.Id
from wgn in dep.Wagons
select new Record
{
Id = dep.Id,
Number = wgn.Number,
Weight = wgn.Weight,
Street = adr.Street
}).ToList();

Or less readable LINQ with extension methods :)
IEnumerable<Record> records =
Depos.Join(Adresses,
myTrain => train.Id,
addr => addr.Id,
(myTrain, addr) => myTrain.Wagons
.Select(wagon => new Record
{
Id = addr.Id,
Street = addr.Street,
Number = wagon.Number,
Weight = wagon.Weight
}))
.SelectMany(myWagons => myWagons);
As you see SelectMany method is key method for this query

Related

How to use access all rows of type List<T> in C# .NET Framework?

I have a Model called SalesItemModel which has properties such as SaleItemId, SalesID, ProductID, Quantity, and UnitPrice. I pull list from database using SalesItemService.ListSalesItemsDataBySaleID(salesID).
public class SalesItemModel
{
public int SalesItemID { get; set; }
public int SalesID { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
public Nullable<decimal> UnitPrice { get; set; }
public double Quantity { get; set; }
}
Pulling Sales Items:
var salesItem = SalesItemService.ListSalesItemsDataBySaleID(SalesID);
And I want to access quantity and product ID of every row of the returned list to edit data on stock table using those data.
If you just want to access the data in list, you can try the below loop.
foreach(var item in salesItem)
{
item.Quantity = 10;
item.ProductId = 20;
}
var tests = new List<Test>
{
new Test{Name = "Abc", Age = 1},
new Test{Name = "Abc2", Age = 12},
new Test{Name = "Abc3", Age = 13},
new Test{Name = "Abc4", Age = 14},
};
tests = tests.Select(x=>
{
x.Age = 2;
return x;
}).ToList();
Example which you can use.

Convert flat db row data to nested typed objects linq

I'm getting the results of a sql outer join as flat results in an IEnumerable, and would like to convert them to nested typed objects in linq. From something like this:
[{id: 1, industryId: 1}, {id:1, industryId: 2}, {id:2, industryId: 1} etc..]
to something like this:
list of Company [{id: 1, list of Industry{industryId: 1, 2}, {id: 2, list of Industry{industryId: 1}}]
I'm currently trying a solution with GroupBy:
Companies = flatDbRows
.GroupBy(
row => row.CompanyId,
(key, value) => new CompanyModel
{
CompanyId = value.First().CompanyId,
CompanyName = value.First().CompanyName,
Industries = value
.GroupBy(
row => new { row.IndustryId, row.Industry },
(k, v) => new IndustryModel() { IndustryId = k.IndustryId, Name = k.Industry }
)
.Where(x => x.IndustryId != 0)
.ToList(),
}).ToList();
}
but it doesn't feel great, especially with all the value.First() I'm using to get the values that only belong to each grouped company. Is there something more appropriate? Group join sounded more like what I wanted, but I'm having trouble understanding how to apply it to a single list. I'm open to using query syntax instead of the lambdas if that's easier.
I'm trying to go from this model (where company-related info will be duplicated for each outer joined industry result):
public class CompanyFlatDbRowsModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public int IndustryId{ get; set; }
public string Industry { get; set; }
}
to this:
public class CompanyModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public IEnumerable<IndustryModel> Industries { get; set; }
}
// FULL edit after providing your models
public class TestClass
{
public class CompanyModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public List<IndustryModel> Industires { get; set; }
}
public class IndustryModel
{
public int IndustryId { get; set; }
public string IndustryName { get; set; }
}
public class CompanyFlatDbRowsModel
{
public CompanyFlatDbRowsModel()
{
}
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public int IndustryId { get; set; }
public string Industry { get; set; }
}
[Fact]
public void Test()
{
var data = new List<CompanyFlatDbRowsModel>
{
new CompanyFlatDbRowsModel
{
CompanyId = 1,
CompanyName = "Company 1",
IndustryId = 1,
Industry = "Industry 1"
},
new CompanyFlatDbRowsModel
{
CompanyId = 1,
CompanyName = "Company 1",
IndustryId = 2,
Industry = "Industry 2"
},
new CompanyFlatDbRowsModel
{
CompanyId = 2,
CompanyName = "Company 2",
IndustryId = 3,
Industry = "Industry 3"
},
new CompanyFlatDbRowsModel
{
CompanyId = 2,
CompanyName = "Company 2",
IndustryId = 4,
Industry = "Industry 4"
},
};
var result = data.GroupBy(x => x.CompanyId)
.Select(x => new CompanyModel()
{
CompanyId = x.Key,
CompanyName = x.First().CompanyName,
Industires = x.Select(y=> new IndustryModel
{
IndustryName = y.Industry,
IndustryId = y.IndustryId
}).ToList()
}).ToList();
foreach (var item in result)
{
var text = $"Company id : {item.CompanyId}, industries : {string.Join(',',item.Industires.Select(x=>$"(name: {x.IndustryName}, id: {x.IndustryId})"))}";
Debug.WriteLine(text);
}
}
}
output:
Company id : 1, industries : (name: Industry 1, id: 1),(name: Industry 2, id: 2)
Company id : 2, industries : (name: Industry 3, id: 3),(name: Industry 4, id: 4)
edit:
alternatively you can do as below, however the "first" thing still occurs somewhere, I have tried also the GroupJoin but it doesn't really help in that case.
var otherResult = data.Select(x =>
new CompanyModel
{
CompanyId = x.CompanyId,
CompanyName = x.CompanyName,
Industires = data
.Where(y => y.CompanyId == x.CompanyId)
.Select(y => new IndustryModel
{
IndustryId = y.IndustryId,
IndustryName = y.Industry
}).ToList()
})
.GroupBy(y => y.CompanyId)
.Select(x => x.First())
.ToList();
edit:
one more approach without using "first"
var anotherResult = data.GroupBy(x => x.CompanyId)
.Select(x =>
{
var companyModel = new CompanyModel()
{
CompanyId = x.Key
};
companyModel.Industires = x.Select(y =>
{
companyModel.CompanyName = y.CompanyName; // assignign here occurs multiple times however with the same value
return new IndustryModel
{
IndustryId = y.IndustryId,
IndustryName = y.Industry
};
}).ToList();
return companyModel;
}).ToList();

How can I join a list of employees and genders using linq

I have retrieve a list of employees. my employee class columns(employeeId, lastname, genderid)
List<m_employees> Items = new List<m_employees>
{
new m_employees{ employeeid = 1, lastname = "mike", genderid = 1 },
new m_employees{ employeeid = 2, lastname = "jeni", genderid = 2 }
};
then i have my gender class columns (id, title)
List<m_genders> genders = new List<m_genders>
{
new m_genders{ id = 1, title = "Male" },
new m_genders{ id = 2, title = "Female" }
};
//then i tried joining the retrieved list of employees to the genders
var x = from emp in Items
join sex in genders
on emp.genderid equals sex.id
into a from b in a.DefaultIfEmpty(new m_genders())
select new
{
emp.lastname,
emp.genderid,
sex = b.title
};
red error line is showing to the keyword join and says "the type of one of the expressions in the join clause is incorrect..."
how can i join them properly?
This happens because types emp.genderid, sex.id are different and you need to cast or convert them explicitly like that:
(int)emp.genderid equals sex.id
I was able to reproduce the error with the following class definition:
class m_genders
{
public int id { get; set; }
public string title { get; set; }
}
class employee
{
public int id;
public uint genderid;
public string lastname { get; set; }
}
Your question is not clear, the code work without any problem :
namespace WindowsFormsApp1
{
public class m_genders
{
public int id;
public string title;
}
public class m_employees
{
public int employeeid { get; set; }
public int genderid { get; set; }
public string lastname { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
List<m_genders> genders = new List<m_genders>
{
new m_genders {id = 1, title = "Male"},
new m_genders {id = 2, title = "Female"}
};
List<m_employees> Items = new List<m_employees>
{
new m_employees{ employeeid = 1, lastname = "mike", genderid = 1 },
new m_employees{ employeeid = 2, lastname = "jeni", genderid = 2 }
};
var x = from emp in Items
join sex in genders
on emp.genderid equals sex.id
into a
from b in a.DefaultIfEmpty(new m_genders())
select new
{
emp.lastname,
emp.genderid,
sex = b.title
};
}
}
}

Use LINQ to join 2 objects for each of its properties

I have created 2 models to store the results of an sql query. Now I would like to join them for each of the week's... (week1 = Record_id, week2 = Record_id)
to get a new Object in which I would have all the data from the 1st model, as well as map data from the "Category" Model to it.
I created a new Model for it, but I am not sure how to write a linq query
First Model:
public class CustomData
{
public string full_name { get; set; }
public string location { get; set; }
public int week1 { get; set; }
public int week2 { get; set; }
public int week3 { get; set; }
}
Second Model:
public class Category
{
public int Record_ID { get; set; }
public int Color{ get; set; }
public string Name { get; set; }
}
New Model for end result:
public class WeekView
{
public string full_name { get; set; }
public string location { get; set; }
public Category week1 { get; set; }
public Category week2 { get; set; }
public Category week3 { get; set; }
}
This should work:
List<CustomData> list = new List<CustomData>();
list.Add(new CustomData() { full_name = "test", location = "test", week1 = 0, week2 = 1, week3 = 2 });
list.Add(new CustomData() { full_name = "test2", location = "test2", week1 = 0, week2 = 12, week3 = 22 });
List<Category> categories = new List<Category>();
categories.Add(new Category { Color = 0, Name = "testName", Record_ID = 0 });
categories.Add(new Category { Color = 1, Name = "testName1", Record_ID = 1 });
categories.Add(new Category { Color = 2, Name = "testName2", Record_ID = 2 });
categories.Add(new Category { Color = 3, Name = "testName3", Record_ID = 12 });
categories.Add(new Category { Color = 4, Name = "testName4", Record_ID = 22 });
List<WeekView> results = new List<WeekView>();
results.AddRange(list.Select(x=>
new WeekView() { full_name = x.full_name,
location = x.location,
week1 = categories.FirstOrDefault(c => c.Record_ID == x.week1),
week2 = categories.FirstOrDefault(c => c.Record_ID == x.week2),
week3 = categories.FirstOrDefault(c => c.Record_ID == x.week3)
}));
Try out the following:
var result = (from cd in CustomDatas
join ca1 in Categories on cd.week1 equals ca.Record_ID into ca1r
from ca1 in ca1r.DefaultIfEmpty()
join ca2 in Categories on cd.week2 equals ca.Record_ID into ca2r
from ca2 in ca2r.DefaultIfEmpty()
join ca3 in Categories on cd.week3 equals ca.Record_ID into ca3r
from ca3 in ca3r.DefaultIfEmpty()
select new {
full_name = cd.full_name,
location = cd.location,
week1 = ca1,
week2 = ca2,
week3 = ca3
}

RavenDB - Indexing and querying complex hierarhical data (nested properties)

I have a docuemnt like this:
public class Order
{
public string ClientName { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public string ProductCode { get; set; }
public int Quantity { get; set; }
}
And I need to query collection of theese documents like this:
var q = session.Query<Order_Index.Result, Order_Index>()
.Where(o => o.ClientName.StartsWith("Jho") &&
o.Items.Any(i => i.ProductCode == "Book" && i.Quantity >= 10))
.OfType<Order>();
Every example of indexing and querying hierarhical data, that I found, shows only case, when only one property of complex nested object is used in separate query expression. e.g.:
var q = session.Query<Order_Index.Result, Order_Index>()
.Where(o => o.ClientName.StartsWith("Jho") &&
o.ItemProductCodes.Any(c => c == "Book") &&
o.ItemQuantities.Any(qty => qty >= 10))
but none of them consider my situation.
I tried to index ProductCode and Quantity as separate collections and then join them by collection index while querying, but this throws some kind of Linq translation exception. I wonder, is there any opportunity to do this kind of querying in RavenDB?
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Order> session = new List<Order>() {
new Order() { ClientName = "Jho", Items = new List<OrderItem>() {
new OrderItem() { ProductCode = "abc", Quantity = 1},
new OrderItem() { ProductCode = "def", Quantity = 4},
new OrderItem() { ProductCode = "Book", Quantity = 5},
new OrderItem() { ProductCode = "jkl", Quantity = 10}
}
},
new Order() { ClientName = "Mary", Items = new List<OrderItem>() {
new OrderItem() { ProductCode = "mno", Quantity = 2},
new OrderItem() { ProductCode = "pqr", Quantity = 3},
new OrderItem() { ProductCode = "stu", Quantity = 4},
new OrderItem() { ProductCode = "vwx", Quantity = 5}
}
},
new Order() { ClientName = "Jho", Items = new List<OrderItem>() {
new OrderItem() { ProductCode = "abc", Quantity = 28},
new OrderItem() { ProductCode = "cdf", Quantity = 7},
new OrderItem() { ProductCode = "Book", Quantity = 26},
new OrderItem() { ProductCode = "jkl", Quantity = 5}
}
}
};
var q = session.Where(o => o.ClientName.StartsWith("Jho") && o.Items.Where(i => i.ProductCode == "Book" && i.Quantity >= 10).Any()).ToList();
}
}
public class Order
{
public string ClientName { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public string ProductCode { get; set; }
public int Quantity { get; set; }
}
}

Categories

Resources