I am looking to join 3 tables which I am getting as List of objects. These are my three tables:
Employee
Department
Category
Employee DepartmentID and CategoryID is used to join Department and Category Table.
This is how my Linq Join looks
var result = from e in Employee.GetAllEmployees()
join d in Department.GetAllDepartments() on e.DepartmentID equals d.ID
join c in Cateory.GetAllCategories() on e.CategoryID equals c.ID
into eGroup
from c in eGroup.DefaultIfEmpty()
select new
{
Employee =e,
Department = d ==null? new Department() : d,
Cateory = c
};
My issue here is that I am getting two different rows for Employee ID = 1 and that's because of two different Categories for ID =1
I would like to get both categories in the same Employee node. Basically two categories for Employee ID = 1.
Expected Result:
CategoryA and CategoryB is tied to Employee Mark.
How do I achieve that?
Thanks for the help !
Here is the code to reproduce what I have so far.
class Program
{
static void Main(string[] args)
{
var result = from e in Employee.GetAllEmployees()
join d in Department.GetAllDepartments() on e.DepartmentID equals d.ID
join c in Cateory.GetAllCategories() on e.CategoryID equals c.ID
into eGroup
from c in eGroup.DefaultIfEmpty()
select new
{
Employee =e,
Department = d ==null? new Department() : d,
Cateory = c
};
Console.WriteLine("Hello World!");
Console.ReadLine();
}
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
public int DepartmentID { get; set; }
public int CategoryID { get; set; }
public static List<Employee> GetAllEmployees()
{
return new List<Employee>()
{
new Employee { EmployeeID = 1, Name = "Mark", DepartmentID = 1, CategoryID = 1 },
};
}
}
public class Department
{
public int ID { get; set; }
public string DepartmentName { get; set; }
public static List<Department> GetAllDepartments()
{
return new List<Department>()
{
new Department { ID = 1, DepartmentName = "TECH"},
new Department { ID = 2, DepartmentName = "HR"},
};
}
}
public class Cateory
{
public int ID { get; set; }
public string CategoryName { get; set; }
public static List<Cateory> GetAllCategories()
{
return new List<Cateory>()
{
new Cateory { ID = 1, CategoryName = "CategoryA"},
new Cateory { ID = 1, CategoryName = "CategoryB"},
new Cateory { ID = 2, CategoryName = "CategoryC"},
};
}
}
}
I don't have a way of testing this really but you should be able to do a left join by updating your query
var result = from e in Employee.GetAllEmployees()
join d in Department.GetAllDepartments() on e.DepartmentID equals d.ID into d_def
from d in d_def.DefaultIfEmpty()
join c in Cateory.GetAllCategories() on e.CategoryID equals c.ID into c_def
from c in c_def.DefaultIfEmpty())
select new
{
Employee =e,
Department = d ==null? new Department() : d,
Cateory = c
};
Here are your results. The two employer have the same ID number
Related
My question is, inside my join of IDs, is it possible to add another column with an ID?
This is what I am trying to do:
My Index:
var orders= db.Orders.ToList();
var colers = db.Colors.ToList();
var result = (from c in orders
join st in colers on c.ID_Orders equals st.id into table1
select new OrderWithColorsViewModel { order =c, colers = table1.ToList()
}).ToList();
return View(result);
My classes:
public partial class Orders
{
public int ID_Orders { get; set; }
public Nullable<System.DateTime> Data_Registo { get; set; }
public string Num_Encomenda { get; set; }
public string Ref_Cliente { get; set; }
}
public partial class Colors
{
public int ID_Orders { get; set; }
public int ID_Line_Color { get; set; }
public string Color{ get; set; }
}
public partial class Quantities
{
public int ID_Orders { get; set; }
public int ID_Line_Color { get; set; }
public int quantity{ get; set; }
}
Of what I am learning right now I have this from my join:
and:
But what I want (I think):
If i am wrong in thinking, correct me, thanks
I leave my solution here for those who need it
var result1 = (from o in order
join c in coler
on o.ID_Programa equals c.ID_Programa into co
group new { o, co } by o.ID_Programa into g
from i in g
select new { order = i.o, colors = i.co }).ToList();
var result2 = (from r1 in result1
from c in r1.colors
join q in quant
on new { orderId = c.ID_Programa, colorlineId = c.ID_Linha_Cor } equals new { orderId = q.ID_Programa, colorlineId = q.ID_Linha_Cor } into p1
from p in p1
join s in statu
on new { orderId = p.ID_Programa, colorlineId = p.ID_Linha_Cor } equals new { orderId = s.ID_Programa, colorlineId = s.ID_Linha_Cor } into q
group new ColorsAndQuantities { coler = c, quant = p1.ToList(), status = q.ToList() } by c.ID_Programa).ToList();
var result = (from r1 in result1
join m in fabric
on r1.order.ID_Programa equals m.ID_Programa into t
from t1 in t
join r2 in result2
on t1.ID_Programa equals r2.Key
select new OrdersColorsViewModel
{
order = r1.order,
malhas = t1,
colers = r2.ToList()
}).ToList();
What is the best practice to convert Sub Query into LINQ,
for example I use this following query :
select VerID = (select top 1 x.INTERNALPACKINGSLIPID from
CUSTPACKINGSLIPVERSION x where a.RECID = x.CUSTPACKINGSLIPJOUR
order by x.VERSIONDATETIME desc),
c.LINENUM, c.RECID, *
from CUSTPACKINGSLIPJOUR a inner join CUSTPACKINGSLIPTRANS c
on a.PACKINGSLIPID = c.PACKINGSLIPID
I simulated you database with classes to get the syntax correct. Make modifications as necessary. There is no best method. Some people like using Where instead of joins. I like joins.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<CUSTPACKINGSLIPVERSIONs> CUSTPACKINGSLIPVERSION = new List<CUSTPACKINGSLIPVERSIONs>();
List<CUSTPACKINGSLIPJOURs> CUSTPACKINGSLIPJOUR = new List<CUSTPACKINGSLIPJOURs>();
List<CUSTPACKINGSLIPTRANSs> CUSTPACKINGSLIPTRANS = new List<CUSTPACKINGSLIPTRANSs>();
var VerId = (from vId in CUSTPACKINGSLIPVERSION
join slipId in CUSTPACKINGSLIPJOUR on vId.INTERNALPACKINGSLIPID equals slipId.RECID
join cId in CUSTPACKINGSLIPTRANS on vId.INTERNALPACKINGSLIPID equals cId.PACKINGSLIPID
select new { vid = vId, slipId = slipId, cId = cId })
.GroupBy(x => x.vid.VERSIONDATETIME)
.OrderBy(x => x.Key)
.FirstOrDefault()
.Select(x => new { linenum = x.cId.LINENUM, recid = x.cId.RECID })
.ToList();
}
}
public class CUSTPACKINGSLIPVERSIONs
{
public int INTERNALPACKINGSLIPID { get; set; }
public DateTime VERSIONDATETIME { get; set; }
}
public class CUSTPACKINGSLIPJOURs
{
public int RECID { get; set; }
public int PACKINGSLIPID { get; set; }
}
public class CUSTPACKINGSLIPTRANSs
{
public int PACKINGSLIPID { get; set; }
public int LINENUM { get; set; }
public int RECID { get; set; }
}
}
You have this in your query and I am assuming it is a typo: a.RECID = x.CUSTPACKINGSLIPJOUR because CUSTPACKINGSLIPJOUR is the collection name. Therefore, I used SomeId instead. But this should give you the idea:
Do a subquery within the projection. You will also need to order by descending and then take the first record-this will be like top 1. Here is the query:
var query = from a in CUSTPACKINGSLIPJOUR
join c in CUSTPACKINGSLIPTRANS on a.PACKINGSLIPID equals c.PACKINGSLIPID
select new
{
VerID = (from x in CUSTPACKINGSLIPVERSION
where a.RECID == x.SomeId select x)
.OrderByDescending(o => o.VERSIONDATETIME)
.First().INTERNALPACKINGSLIPID,
c.LINENUM,
c.RECID
};
You can test it with the following collections:
var CUSTPACKINGSLIPJOUR = new List<CUSTPACKINGSLIPJOUR> { new CUSTPACKINGSLIPJOUR { PACKINGSLIPID = 1, RECID = 1 },
new CUSTPACKINGSLIPJOUR { PACKINGSLIPID = 2, RECID = 2 }};
var CUSTPACKINGSLIPTRANS = new List<CUSTPACKINGSLIPTRANS>
{
new CUSTPACKINGSLIPTRANS { LINENUM = 1, RECID = 1, PACKINGSLIPID = 1 }
};
var CUSTPACKINGSLIPVERSION = new List<CUSTPACKINGSLIPVERSION>
{
new CUSTPACKINGSLIPVERSION { INTERNALPACKINGSLIPID = 1, SomeId = 1, VERSIONDATETIME = DateTime.Today.AddDays(-1) },
new CUSTPACKINGSLIPVERSION { INTERNALPACKINGSLIPID = 2, SomeId = 1, VERSIONDATETIME = DateTime.Today }
};
It will be the same query if you use a DbSet<T>.
Suppose you have those setup:
public class TBL_CUSTPACKINGSLIPVERSION
{
public int CUSTPACKINGSLIPVERSION_ID { get; set; }
public int INTERNALPACKINGSLIPID { get; set; }
public DateTime VERSIONDATETIME { get; set; }
}
public class TBL_CUSTPACKINGSLIPJOUR
{
public int RECID { get; set; }
public int PACKINGSLIPID { get; set; }
}
public class TBL_CUSTPACKINGSLIPTRANS
{
public int PACKINGSLIPID { get; set; }
public int LINENUM { get; set; }
public int RECID { get; set; }
}
var CUSTPACKINGSLIPVERSION = new List<TBL_CUSTPACKINGSLIPVERSION>();
var CUSTPACKINGSLIPJOUR = new List<TBL_CUSTPACKINGSLIPJOUR>();
var CUSTPACKINGSLIPTRANS = new List<TBL_CUSTPACKINGSLIPTRANS>();
Then you can setting up the combined query as given in example below (assumed CUSTPACKINGSLIPVERSION_ID is the identity key which used in comparison between CUSTPACKINGSLIPJOUR & CUSTPACKINGSLIPTRANS):
var query = (from a in CUSTPACKINGSLIPJOUR
join c in CUSTPACKINGSLIPTRANS
on a.PACKINGSLIPID equals c.PACKINGSLIPID
select new {
VerID = (from x in CUSTPACKINGSLIPVERSION
where a.RECID == x.CUSTPACKINGSLIPVERSION_ID // should be an identity column/primary key to compare with
orderby x.VERSIONDATETIME descending
select x).FirstOrDefault().INTERNALPACKINGSLIPID,
c.LINENUM,
c.RECID
}).ToList();
Note that your query includes * at the end of SELECT statement which may indicate the query will return all records from both tables involved in join clause. If you want to return entire records of CUSTPACKINGSLIPJOUR only but not return all CUSTPACKINGSLIPTRANS, include a into the select new statement (incorporates SQL usage of a.*):
select new {
VerID = (from x in CUSTPACKINGSLIPVERSION
where a.RECID == x.CUSTPACKINGSLIPVERSION_ID // should be an identity column/primary key to compare with
orderby x.VERSIONDATETIME descending
select x).FirstOrDefault().INTERNALPACKINGSLIPID,
c.LINENUM,
c.RECID,
a // used if you want to return all records from CUSTPACKINGSLIPJOUR
}).ToList();
I have a wpf c# app.
I have to list collections.
I want to join these 2 lists and return the results that match a criteria.
I want the result to be loaded into a new list/model.
This is my code so far:
var Results = from j in res
join c in Customer.GetBaseData() on j.CustomerRef equals c.CustomerRef
where j.JobStatusRef == jobStatusRef
select new {
c.CustomerRef,
c.CustomerId,
c.Add1,
c.Town,
c.FName,
c.SName,
j.DateReq,
j.JobId,
j.JobRef,
j.JobStatus
};
This is my destination model:
public class CustomerJobs
{
public int JobId { get; set; }
public string CustomerRef { get; set; }
public string DateReq { get; set; }
public string JobRef { get; set; }
public string JobStatus { get; set; }
public int CustomerId { get; set; }
public string SName { get; set; }
public string FName { get; set; }
public string Add1 { get; set; }
public string Town { get; set; }
}
I do not know how to do this final step?
Instead of creating an anonymous type with new { ... }, directly use your model in the select:
var Results = from j in res
join c in Customer.GetBaseData() on j.CustomerRef equals c.CustomerRef
where j.JobStatusRef == jobStatusRef
// Note the "new CustomerJobs" part.
select new CustomerJobs {
c.CustomerRef,
c.CustomerId,
c.Add1,
c.Town,
c.FName,
c.SName,
j.DateReq,
j.JobId,
j.JobRef,
j.JobStatus
};
When you select in linq you can specify the type of the object like:
var Results = from j in res
join c in Customer.GetBaseData() on j.CustomerRef equals c.CustomerRef
where j.JobStatusRef == jobStatusRef
select new CustomerJobs {
CustomerRef = c.CustomerRef,
CustomerId = c.CustomerId,
Add1 = c.Add1,
Town = c.Town,
FName = c.FName,
SName = c.SName,
DateReq = j.DateReq,
JobId = j.JobId,
JobRef = j.JobRef,
JobStatus = j.JobStatus
};
I am attempting to join two lists (flist and slist) on the ID column. List definitions, class definitions, list contents, and desired results are displayed below.
List<first> flist= new List<first>();
List<second> slist= new List<second>();
public class first
{
public string name { get; set; }
public int ID{ get; set; }
public string itemAttr { get; set; }
}
public class second
{
public int ID{ get; set; }
public string itemAttr{ get; set; }
}
List contents
flist:
apples | 1
bananas| 2
trees | 3
slist:
1 | fruit
3 | not-fruit
Desired result:
flist:
apples | 1 | fruit
bananas | 2 |
trees | 3 | not-fruit
List<first> flist= new List<first>();
List<second> slist= new List<second>();
var result = from f in flist
join s in slist on f.ID equals s.ID into g
select new {
f.name,
f.ID,
itemAttr = g.Any() ? g.First().itemAttr : null
};
Try this
foreach(var f in first)
{
foreach(var s in second)
{
if(f.ID == s.ID)
{
f.fAttr = item.itemAtrr;
}
}
}
You can use a "left-outer" join with Linq:
var joined = from l1 in flist
join l2 in slist on l1.ID equals l2.ID into gj
from l2_sub in gj.DefaultIfEmpty()
select new {
name = l1.name,
ID = l1.ID,
itemAttr = l2_sub == null ? String.Empty : l2_sub.itemAttr
};
namespace WindowsFormsApplication26
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<first> flist = new List<first>();
List<second> slist = new List<second>();
flist.Add(new first("apples", 1));
flist.Add(new first("bananas", 2));
flist.Add(new first("trees", 3));
slist.Add(new second(1, "Fruit"));
slist.Add(new second(2, ""));
slist.Add(new second(3, "Not-Fruit"));
var result = (from t in flist
join x in slist
on t.ID equals x.ID
select new
{
Name = t.name,
Id = t.ID,
attrib = x.itemAttr
}).ToList();
}
public class first
{
public first()
{
}
public first(string n, int id)
{
name = n;
ID = id;
}
public string name { get; set; }
public int ID { get; set; }
}
public class second
{
public second()
{
}
public second(int id, string itm)
{
ID = id;
itemAttr = itm;
}
public int ID { get; set; }
public string itemAttr { get; set; }
}
}
}
What's the problem? Create a new class which third with parameters: ID, name, itemAttr. Create new List with this class and will write in needed position needed data.
I've two Tables lets simply say :
Products : ProductID, ProductName
Orders : OrderID,ProductID,Amount,Status
I want to write a LINQ query in C# which would
select ProductName,Sum(Amount) where Status = 1
I am stuck with this simple query :(
class Program
{
class Product
{
public int ProductID { get; set; }
public string ProductName {get; set; }
public Product(int ProductID, string ProductName)
{
this.ProductID = ProductID;
this.ProductName = ProductName;
}
}
class Order
{
public int OrderID { get; set; }
public int ProductID { get; set; }
public decimal Amount { get; set; }
public int Status { get; set; }
public Order(int OrderID, Product product, decimal Amount, int Status)
{
this.OrderID = OrderID;
this.ProductID = product.ProductID;
this.Amount = Amount;
this.Status = Status;
}
}
private static Product[] Products;
private static Order[] Orders;
static void Main(string[] args)
{
Products = new Product[]
{
new Product(1, "Bolt"),
new Product(2, "Nut"),
new Product(3, "Mounting Plate A"),
new Product(4, "Mounting Plate B")
};
Orders = new Order[]
{
new Order(1, Products[0], 1.12M, 0),
new Order(2, Products[1], 0.66M, 1),
new Order(3, Products[2], 4.12M, 0),
new Order(4, Products[0], 1.11M, 1),
new Order(5, Products[1], 0.67M, 1)
};
var results = from p in Products
join o in Orders on p.ProductID equals o.ProductID
where o.Status == 1
group o by p
into orderTotals
select new {ProductName = orderTotals.Key.ProductName, TotalAmount = orderTotals.Sum(o => o.Amount)};
foreach(var result in results)
{
Console.WriteLine("{0}: {1}", result.ProductName, result.TotalAmount);
}
}
}
Output:
Bolt: 1.11
Nut: 1.33
Although not the optimal, but this should work:
var interim =
from o in orders
where o.Status == 1
select new { o.OrderID, o.ProductID, o.Amount, o.Status};
var final =
from p in products
join x in interim on p.ProductID equals x.ProductID into g
select new { p.ProductName, Total = g.Sum(y => y.Amount) };