Joining 2 lists of objects based on object id - c#

In my web application I am fetching 2 lists of objects from database.
First list of objects Employee
1
Name: Tom
Week1: 1
Week2: 3
Week3: 7
2
Name: Mike
Week1: 2
Week2: 1
Week3: 7
Second list of objects listOfId
1
id: 1
color: green
symbol: AT
2
id: 2
color: red
symbol: TB
3
id: 3
color: blue
symbol: TD
I would like to be able now to display it in a form of table, where for each of the weeks, I display this weeks color and symbol (each week matched on Employee.Week# = listOfId.id)
Something like this
Name | Week1 | Week1 Color | Week1 Symbol | Week2 | Week 2 Color etc...
Tom 1 green AT 3 blue
Mike 2 red TB 1 green
In total I will have constant 20 weeks for each employee.
I considered writing a SQL query which would take in week id, and return color and symbol. But for 50 people * 20 weeks... I would need to run this query 1000 times.
I am looking for better approach to solving this issue
my Models:
public class WeekViewModel
{
public int Id{ get; set; }
public string ShortNAme { get; set; }
public string Description { get; set; }
public int Color { get; set; }
}
}
public class EmployeeWeekViewModel
{
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; }
}

If I'm getting your correct, you have two lists coming from DB:
employeesList which represents the employees with their corresponding weeks ID
weeksList which represents the weeks for an employee.
Now, you want to join these two lists to display the information in a simple table format. I would do something like that:
public class EmployeeWeekViewModel{
public string EmployeeName{get;set;}
public WeekViewModel Week1 {get;set;}
public WeekViewModel Week2 {get;set;}
...
public WeekViewModel Week20 {get;set;}
}
public class WeekViewModel{
public int Id{get;set;}
public string Color{get;set;}
public string Symbol{get;set;}
}
employeesList.Select(t=> new EmployeeWeekViewModel(){
EmployeeName = t.Name,
Week1 = weeksList.FirstOrDefault(w => w.id == t.Week1).Select(w => new WeekViewModel(){
Id = w.id,
Color = w.color,
Symbol = w.symbol
}),
Week2 = weeksList.FirstOrDefault(w => w.id == t.Week2).Select(w => new WeekViewModel(){
Id = w.id,
Color = w.color,
Symbol = w.symbol
}),
...
});
In order to not make a request for each week, I would suggest send to you query a list of week Ids to get them once (checkout this example).

Related

Linq two table with sum column

My RowMultiplevaluw table is
public class RowMultipleValues
{
public int ID { get; set; }
public String Year{ get; set; }
public string country { get; set; }
public decial Admin { get; set; }
public decimal Finance { get; set; }
public virtual ICollection<UsedAmount> UsedAmount { get; set; }
}
My used amount table is
public class UsedAmount
{
public int ID { get; set; }
public string Year{ get; set; }
public string country { get; set; }
public decial UsedAmount { get; set; }
public int RowMultipleValues ID { get; set; }
Public virtual RowMultibleValue RowMultibleValue { get; set; }
}
My query is
var query = from mtv in context.multiplerowvaluetable
join usd in dbcontext.usedtsble on mtv.year equal usd.year group g by mtv.country into g
select new { country =g.key,sumadmincolumn =g.sum(Admin),sumfinancecolumn = g.sum(finance) }).tolist();
Result which I want is
ID Year Country Admin. UsedAdmin Finance UsedFinance
1. 2017 USA 100 50 200 300
2. 2017 China 300 300 500 400
Total. 400 350 700 700
Please help me my model design and query for result.Thank.
So you want to join every MultipleValue with the UsedAmount on equal year value. Then group the result into groups of joined items with same country. Finally from every group create one object with the country, the sum of all Admin values and the sum of all finance values.
// first join the two collections on same year.
// we only need properties Country, Admin, Finance:
var result = myDbContext.MultipleRowValueTable.Join(myDbContext.UsedAmountTable,
multipleRow => multipleRow.Year, // from every multipleRow take the year
usedAmount => usedAmount.Year, // from every usedAmount take the year
(multipleRow, usedAmount) => new // when they match make a new object
{
Country = multipleRow.Country,
Admin = multipleRow.Admin,
UsedAdmin = usedAmount.Admin,
Finance = multipleRow.Finance,
UsedFinance = usedAmount.Finance,
})
// group the elements from this join table into groups with same Country
.GroupBy(joinedItem => joinedItem.Country, // all items in the group have this Country
joinedItem => new // the elements of the group
{
Admin = joinedItem.Admin,
UsedAdmin = joinedItem.UsedAdmin,
Finance = joinedItem.Finance,
UsedFinance = joinedItem.UsedFinance,
})
// finally: from every group take the Key (which is the Country)
// and the sum of the Admins and Finances in the group
.Select(group => new
{
Country = group.Key,
SumAdminColumn = group
.Select(groupElement => groupElement.Admin)
.Sum(),
... // others are similar
});
// from every group take the elements and sum the properties
.Select(group => new
{
Id = multipleRowValue.Id,
Year = multipleRowValue.Year,
Country = multipleRowValue.Country,
}

Join Parent, Child and GrandChild tables with latest record from grandchild table using LinQ in C#

Please note this is just to simulate the example but not the actual tables itself.
Apologies for long question
I have three tables Vendor, Product and Orders. They are linked like below.
Vendor --> Id, Name, Location (this table has all info regarding vendor)
Product --> Id, VendorId, Name, Description (this table has all the product that vendor sells)
Orders --> Id,ProductId,Date (this table has all the Orders placed for that product)
Vendor has One to One relationship with Product table but some of the vendors may not have product at all.
Product table has one to many relationship with Orders table
I am trying to get the latest Order placed for a Vendor using linq.
Example.
Vendor :
1 | Microsoft | Seattle
2 | Apple | California
3 | Amazon | Seattle
Product :
1 | 1 | MS Office | Office Suite
2 | 2 | iPhone | Smart Phone
Order:
1 | 1 | 05/27/2016
2 | 1 | 06/07/2016
3 | 2 | 04/17/2016
4 | 2 | 06/01/2016
Expected Result:
1 | Microsoft | Seattle
1 | 1 | MS Office | Office Suite
2 | 1 | 06/07/2016
2 | Apple | California
2 | 2 | iPhone | Smart Phone
4 | 2 | 06/01/2016
3 | Amazon | Seattle
null
null
var vendor = db.Vendor.Include(x => x.Product.Select(s => s.Order)).OrderBy(a => a.Name).Select(s => new VendorModel
{
Id = c.Id,
Name = c.Name,
Location = c.Location
Product = c.Product.Select(m => new ProductModel
{
Id = m.Id,
VendorId = m.VendorId,
Name = m.Name,
Description = m.Description,
}).FirstOrDefault(),
Order = c.Order.Select(m => new OrderModel
{
Id = m.Id,
ProductId = m.ProductId,
Date = m.Date,
}).OrderBy(o=>o.Date).FirstOrDefault(),
});
public class VendorModel
{
public ApplicationModel() { }
public ApplicationModel(int id, string name, string location)
{
this.Id = id;
this.Name = name;
this.Location = location;
}
public int Id { get; set; }
public string Name { get; set; }
public string Location{ get; set; }
public virtual ProductModel Product { get; set; }
public virtual OrderModel Order { get; set; }
}
public class ProductModel
{
public ProductModel() { }
public ProductModel(int id, int vendorId, string name, string description)
{
this.Id = id;
this.VendorId = vendorId;
this.Name = name;
this.Description = description;
}
public int Id { get; set; }
public int VendorId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public VendorModel Vendor { get; set; }
}
public class OrderModel
{
public OrderModel() { }
public OrderModel(int id, int productId, DateTime date)
{
this.Id = id;
this.ProductId = productId;
this.Date = date;
}
public int Id { get; set; }
public int ProductId { get; set; }
public DateTime Date { get; set; }
public ProductModel Product { get; set; }
}
As Vendor might have null value, I think you should use Left outer joins. Here is how you could implement left outer joins with LINQ.
var query = from v in Vendor
join p in Product on v.id equals p.vendorId into t1
from vp in t1.DefaultIfEmpty()
join o in Orders on p.id equals o.productId t2
from vpo in t2.DefaultIfEmpty()
orderby v.Name, vpo.date
select new
{
v.Name, v.Location,
productId=(int?)vp.id, // To handle null value if id(ProductId) is specified as not null in Product table.
vp.Name, vp.Description,
orderId = (int?)vpo.id, // To handle null value if id(OrderId) is specified as not null in Orders table.
vpo.date
}.ToList();

List that groups by property and then counts distinct values of another property and writes count to list property

I have a list that contains about 50 properties of a class. What I'm struggling with is I"m trying to take a count of the distinct values of two properties This "count" number then needs to be added on to the end of the list of each group by.
For example: here is my class
public class ListType
{
public ListType()
{
}
public string ID { get; set; }
public string REGSID { get; set; }
public string county { get; set; }
public string act_loc { get; set; }
public string eviofnd { get; set; }
public string hmonth { get; set; }
public string hisnc { get; set; }
public string hinc { get; set; }
public string FIPS { get; set; }
public decimal back00 {get; set;}
public decimal ann00 { get; set; }
public int countDistinctID {get;set;}
}
I need to take a count of distinct IDS of each distinct FIPS and then that count of the distinct IDS is set to countDistinctID property of each grouped FIPS.
ID FIPS other columns(still need this data though)
4 1 ......
5 2 ....
4 1 ....
4 2 ....
1 3 .....
1 2 ....
2 1 .....
What I need is this...
ID FIPS other columns count
4 1 ...... 2 3 rows with FIPS =1 then 2 distinct ID's per FIPs=1
5 2 .... 3 3 rows w/FIPS=2 3 distinct IDS per FIps=2
4 1 .... 2
4 2 .... 3
1 3 ..... 1 1 row w/fips=3 1 distinct id perFIPS=3
1 2 .... 3
2 1 ..... 2
I've parsed in a file and I write all the columns to a list called List data
what I ultimately need to do after I take count of distinct ID's is then set that count value to countDistinctID of the original "data" list and do that for each distinct FIPS and ID per that distinct FIPS
census.countDistinctID
Try this
var distinct = censu.Select(a => a.Select(x=>x.ID).Distinct().Count());
var censu = data.GroupBy(a => a.FIPS).ToList();
foreach (var grp in censu)
{
var count = grp.Select(p=>p.ID).Distinct().Count();
foreach (var d in grp)
d.countDistinctID = count;
}

Merge two DataTables with LINQ

My question is similar too THIS
I have two DataTables:
DataTable 1:
Column 1: Date
Column 2: Requests 1
DataTable 2:
Column 1: Date
Column 2: Requests 2
I need the bellow result:
New DataTable:
Column 1: Date
Column 2: Requests 1
Column 3: Requests 2
Expected Result:
Date Requests 1 Requests 2 Total
15/08/2013 25 40 60
14/08/2013 40 60 100
13/08/2013 40 0 25
12/08/2013 0 80 80
What I did until now:
DataTable Lista_1 = ds.Tables[0];
DataTable Lista_2 = ds.Tables[1];
var myLINQ = from l1 in Lista_1.AsEnumerable()
join l2 in Lista_2.AsEnumerable()
on l1.Field<DateTime>("Date") equals l2.Field<DateTime>("Date")
select new
{
dateRelatorio = l1.Field<DateTime>("Date"),
request1Relatorio = l1.Field<int>("Total"),
request2Relatorio = l2.Field<int>("contagem"),
total = l1.Field<int>("Total") + l2.Field<int>("contagem")
};
And I would like to return an IList collection (System.Collections.IList)
UPDATE
listReturn = new List<Stats>();
public class Stats
{
public DateTime dateRelatorio { get; set; }
public int request1Relatorio { get; set; }
public int request2Relatorio { get; set; }
public int total { get; set; }
}
UPDATE 2
May have dates in List_1 that there is not in List_2 and vice versa, so the Request need to be 0.
If you need this thing to be encapsulated in a method, you should create a class to be returned:
public class DailyReport
{
public DateTime Date {get; set;}
public int Requests1 {get; set;}
public int Requests2 {get; set;}
public int Total // this can be calculated on the fly
{
get {return Requests1 + Requests2; }
}
}
And then do
public List<DailyReport> GetDailyReports(..parameters if needed...)
{
...
var myLINQ = from ...
select new DailyReport {
Date = l1.Field<DateTime>("Date"),
Requests1 = l1.Field<int>("Total"),
Requests2 = l2.Field<int>("contagem"),
};
return myLINQ.ToList();
}
There are some dirty hacks that could enable you to return an collection of anonymous objects, but I would advise against it.

How can I get two different aggregates in a single LINQ?

I have a list of this object:
public class Customer
{
public int Id { get; set; }
public string EmailAddress { get; set; }
public DateTime ServiceStartDate { get; set; }
public DateTime? BillingStartDate { get; set; }
public string Status { get; set; }
}
In preparation for making a chart displayed on a dashboard I am trying to condense this list into another list of this object:
public class DashboardCustomerConversions
{
public string Month { get; set; }
public int Trials { get; set; }
public int Purchased { get; set; }
}
Where the end result looks something like:
Month Trials Purchases
--------- ------ ---------
Dec 2010 390 250
Jan 2011 345 190
Feb 2011 576 340
I am having a hard time coming up with a LINQ statement that can achieve the desired end result. This statement is very close:
var list = from b in results
group b by new { b.ServiceStartDate.Year, b.ServiceStartDate.Month } into g
select new Test
{
Month = string.Format("{0} {1}", CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(g.Key.Month), g.Key.Year),
Trials = g.Count(),
Purchased = g.Count()
};
The obvious problem in is the "Purchased = g.Count()" line in that it just repeats the Trials result. I would like to count objects where the BillingStartDate.HasValue is true.
Is there a way to restructure the LINQ to make this work?
Edit: I would prefer a fluent style of syntax but I was unable to get the above to work. Answer in any variation would be great.
You need to pass a condition to the Count method.
Purchased = g.Count(q => q.BillingStartDate.HasValue)
So SLaks had the right solution. Here it is written in fluent syntax:
listOfCustomer.GroupBy(c => new { c.ServiceStartDate.Year, c.ServiceStartDate.Month })
.Select(group => new DashboardCustomerConversions()
{
Month = string.Format("{0} {1}", CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(group.Key.Month), group.Key.Year),
Trials = group.Count(),
Purchased = group.Count(c => c.BillingStartDate.HasValue)
});

Categories