LINQ to SQL Union and then Join - c#

I have tables similar like Employee, Manager, Branch, Division, Employee_history
And let us say two tables Employee and Manager share certain columns like employee_id, name, branch_id
Branch table has branch_id
Division table has division_id
Employee_history has emp_hist_id.
All of these tables are one-many relationships
The SQL I want to convert to LINQ is
select b.branch_id, e.employee_id
from division d
join branch b on d.division_id = b.division_id
join
( select employee_id, branch_id
from EMPLOYEE
UNION
select employee_id, branch_id
from MANAGER
) e
on e.branch_id = b.branch_id
join EMPLOYEE_HISTORY eh on eh.employee_id = e.employee_id
How do i do a UNION and then a join. I have put a simplified version of SQL than what I have. In my actual SQL, there are two or three joins before Branch table and one join after the union
And my LINQ looks like (similar to actual code)
from division in divisions
join brnch in Branch on division.division_id equals brnch.division_id
join empl in (
from emplyee in Employee select new { EmployeeId = emplyee.employee_id}, BrnachId = branch_id).Union(
from mngr in Manager select new { EmployeeId = mngr.employee_id, BrnachId = branch_id)
on brnch.branch_id equals empl.BranchId
join emplhistory in EMPLOYEE_HISTORY on empl.EmployeeId equals emplhistory.employee_id
where division.division_type_id = 10
select new
{
//...
}
I am getting the error:
The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.
In the line that starts with 'join empl in ('

Your syntax for the on caluse of Join is slightly off. In C# it is not:
on division.division_id = brnch.division_id
it needs to be:
on division.division_id equals brnch.division_id
This needs to be changed for all of the on clauses.

In LINQ the order of the statements is a little bit reversed, as opposed to SQL. And when making a .Join() make sure the property names and types(!) are equal. You can't simply join an int on an int?, you have to cast the int to be int? also.
In the example below, I suppose the Branch_ID on Employee and Manager are nullable (int?).
DataContext.GetTable<Employee>()
.Select(e => new { e.ID, e.Name, e.Branch_ID })
.Union(DataContext.GetTable<Manager>()
.Select(m => new { m.ID, m.Name, m.Branch_ID }))
.Join(DataContext.GetTable<Branch>(),
u => new { Branch_ID = u.Branch_ID },
b => new { Branch_ID = (int?)b.ID },
(u, b) => new { u.ID, u.Name, u.Branch_ID, b.Branch_Name })
.Select(j => new { j.ID, j.Name, j.Branch_ID, j.Branch_Name });
And to finish it, I applied this to the actual code:
divisions
.Where(d => d.division_type_id == 10)
.Join(branches,
d => (int?)d.division_id,
b => b.division_id,
(d, b) => new { b.branch_id }) // j1
.Join(employees
.Select(e => new { e.employee_id, e.branch_id })
.Union(managers
.Select(m => new { m.employee_id, m.branch_id })),
j1 => (int?)j1.branch_id,
em => em.branch_id,
(j1, em) => new { em.employee_id, em.branch_id }) // j2
.Join(employeeHistory,
j2 => j2.employee_id,
h => h.employee_id,
(j2, h) => new { j2.employee_id, j2.branch_id, h.history_line }) // j3

Related

How to join two tables and group by ID and count in LINQ C# method syntax

I have two tables:
PractitionerSkill { Id, Title }
PractitionerInSkills { Id, PractitionerSkillId ), where PractitionerSkillId is FK into PractitionerSkill
(there are more columns but that is not really important)
And I'm trying to count number of skills pr practitioner.
Using LINQ method syntax, I am trying to do this:
SELECT
S.Id, S.Title, COUNT(*) as [Count] from
PractitionerSkills S INNER JOIN
PractitionerInskills PIS ON S.ID = PIS.PractitionerSkillId
GROUP BY
S.Id, S.Title
ORDER BY
S.Title
Easy in SQL. Notice that I'm getting the ID, title and count in the result.
My current efforts (which is not even method syntax)
var query = from skill in _context.PractitionerSkills
join pis in _context.PractitionerInSkills on skill.Id equals pis.PractitionerSkillId into grp
select new
{
Title = skill.Title,
Count = grp.Count()
};
which is almost there, but I can't get more columns out. I need the Skill.Id (or PractitionerInSkills.PractitionerSkillId)
It's easy in Linq too!
var query = _context.PractitionerSkills.Join(_context.PractitionerInSkills,
ps => new { k1 = ps.Id },
pis => new { k1 = pis.PractitionerSkillId },
(ps, pis) => new { ps.Id, ps.Title })
.GroupBy(r => new { r.Id, r.Title })
.Select(g => new { g.Key.Id, g.Key.Title, Count = g.Count() })
.OrderBy(r => r.Title);

Select multiple joined tables into multiple variables in SQL queries or LINQ

SELECT O.*, U.*, C.*, P.*, S.*
INTO OV, Usuarios, Clientes, Proposta, Status
FROM[dbo].[TB_OV] O
INNER JOIN dbo.TB_Usuarios U on U.id = O.userinsert
INNER JOIN dbo.TB_Clientes C on C.id = O.ENDFAT
INNER JOIN dbo.TB_Status S on S.id = O.status
LEFT JOIN TB_Proposta P on P.id = O.ID_PROP
WHERE O.status = 214 ORDER BY O.DTSOL, O.DtdeFaturamento
I am developing a web system in C# and one of the queries that I am trying to do is this one...
I want to know what is the correct syntax to do that or something like this.
What I need to know exactly is how to select this five tables into five different variables like an object to each one that I can cast later in C# to turn into object typed.
Otherwise, I've tried to do it with LINQ to SQL from C# and I still did not get any results from queries in LINQ to SQL to these tables.
Lambda:
var query = db.TB_OV
.Join(db.TB_Usuarios, OV => OV.USERINSERT, U => U.ID, (OV, U) => new { OV, U })
.Join(db.TB_Clientes, Z => Z.OV.ENDFAT, CL => CL.ID, (Z, CL) => new { Z, CL })
.Join(db.TB_Status, Z => Z.Z.OV.STATUS, ST => ST.ID, (Z, ST) => new { Z, ST })
.Join(db.TB_Proposta, Z => Z.Z.Z.OV.ID_PROP, P => P.ID, (Z, P) => new { Z, P })
.Where(Z => Z.Z.Z.Z.OV.STATUS == 214)
.Select(Z => new OperacoesListaSolFaturamento
{
OV = Z.Z.Z.Z.OV,
Usuarios = Z.Z.Z.Z.U,
Clientes = Z.Z.Z.CL,
Status = Z.Z.ST,
Proposta = Z.P
});
Fluent:
var query = from O in db.TB_OV
join U in db.TB_Usuarios on O.USERINSERT equals U.ID
join C in db.TB_Clientes on O.ENDFAT equals C.ID
join S in db.TB_Status on O.STATUS equals S.ID
join P in db.TB_Proposta on O.ID_PROP equals P.ID
where O.STATUS == 214
select new OperacoesListaSolFaturamento
{
OV = O,
Usuarios = U,
Clientes = C,
Status = S,
Proposta = P
};
Is there any way to do that? Either by LINQ or SQL queries.
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, translating monadic and aggregate operators (DISTINCT, TOP, MIN, MAX etc) into functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { ... }) for multiple columns.
LEFT JOIN is simulated by using into joinvariable and doing another from from the joinvariable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator (?:)and a null test.
Translate IN to .Contains() and NOT IN to !...Contains().
Translate x BETWEEN low AND high to low <= x && x <= high.
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
So the main problem with your fluent query is you didn't translate the LEFT JOIN properly:
var query = from O in db.TB_OV
where O.STATUS == 214
join U in db.TB_Usuarios on O.USERINSERT equals U.ID
join C in db.TB_Clientes on O.ENDFAT equals C.ID
join S in db.TB_Status on O.STATUS equals S.ID
join P in db.TB_Proposta on O.ID_PROP equals P.ID into Pj
from P in Pj.DefaultIfEmpty()
orderby O.DTSOL, O.DtdeFaturamento
select new OperacoesListaSolFaturamento
{
OV = O,
Usuarios = U,
Clientes = C,
Status = S,
Proposta = P
};

Convert SQL to Linq queries in Entity Framework

How do I convert this query to a LINQ query in Entity Framework? I am a new programmer still in school
SELECT
studfirstname, studlastname, grade
FROM
students
INNER JOIN
Student_Schedules ON students.StudentID = Student_Schedules.StudentID
INNER JOIN
Classes ON Student_Schedules.ClassID = Classes.ClassID
INNER JOIN
Subjects ON Classes.SubjectID = Subjects.SubjectID
WHERE
SubjectName = 'Introduction to Art';
As you are new in Lambda and LINQ I tried in the following Lambda to be as descriptive as possible..... You can use the Long Aliases in short form also
student_schedules as ss OR studentsANDstudent_schedules as s_s_sch... Try this ...Hope this helps.... #Abdul Hameed
var filteredData = context.Students // your starting point
.Join(context.Student_Schedules, // the source table of the inner join
students => students.StudentID, // Select the primary key (the first part of the "on" clause in an sql "join" statement)
student_schedules => student_schedules.StudentID),// the foreign key
(students, student_schedules) => new { students, student_schedules })
.Join(context.Classes,
classes => classes.ClassID,
studentsANDstudent_schedules => studentsANDstudent_schedules.student_schedules.ClassID),
(classes, studentsANDstudent_schedules) => new { classes, studentsANDstudent_schedules })
.Join(context.Subjects,
subjects => subjects.SubjectID,
studentsANDstudent_schedulesANDClasses => studentsANDstudent_schedulesANDClasses.classes.SubjectID),
(subjects, studentsANDstudent_schedulesANDClasses) => new { subjects, studentsANDstudent_schedulesANDClasses })
.Where(allMergedTables => allMergedTables.subjects.SubjectName == "Intoduction to Art").ToList();
And this is the shortened version of the above one...
var filteredData = context.Students
.Join(context.Student_Schedules, s => s.StudentID, sch => sch.StudentID),
(s, sch) => new { s, sch })
.Join(context.Classes, c => c.ClassID, s_sch => s_sch.sch.ClassID),
(c, s_sch) => new { c, s_sch })
.Join(context.Subjects, sj => sj.SubjectID, s_sch_c => s_sch_c.c.SubjectID),
(sj, s_sch_c) => new { sj, s_sch_c })
.Where(all => all.sj.SubjectName == "Intoduction to Art")
.ToList();
You can use LINQ syntax:
from student in context.Students
join schedule in context.Student_Schedules on student.StudentID equals schedule.StudentID
join #class in context.Classes on schedule.ClassID equals #class.ClassID
join subject in context.Subjects on #class.SubjectID equals subject.SubjectID
where subject.SubjectName == "Introduction to Art"
var students = context.Students.Include("Student_Schedules")
.Include("Classes")
.Include("Subjects").Where(s => s.Subjects.Contains("Intoduction to Art"));
Info -> https://msdn.microsoft.com/en-us/data/jj574232.aspx

How to join 3 tables with lambda expression?

I have a simple LINQ lambda join query but I want to add a 3rd join with a where clause. How do I go about doing that?
Here's my single join query:
var myList = Companies
.Join(
Sectors,
comp => comp.Sector_code,
sect => sect.Sector_code,
(comp, sect) => new {Company = comp, Sector = sect} )
.Select( c => new {
c.Company.Equity_cusip,
c.Company.Company_name,
c.Company.Primary_exchange,
c.Company.Sector_code,
c.Sector.Description
});
I want to add the following SQL command to the above LINQ query and still maintain the projections:
SELECT
sector_code, industry_code
FROM
distribution_sector_industry
WHERE
service = 'numerical'
The 3rd join would be made with Sector table & Distribution_sector_industry on sector_code.
Thanks in advance.
Just a guess:
var myList = Companies
.Join(
Sectors,
comp => comp.Sector_code,
sect => sect.Sector_code,
(comp, sect) => new { Company = comp, Sector = sect })
.Join(
DistributionSectorIndustry.Where(dsi => dsi.Service == "numerical"),
cs => cs.Sector.Sector_code,
dsi => dsi.Sector_code,
(cs, dsi) => new { cs.Company, cs.Sector, IndustryCode = dsi.Industry_code })
.Select(c => new {
c.Company.Equity_cusip,
c.Company.Company_name,
c.Company.Primary_exchange,
c.Company.Sector_code,
c.Sector.Description,
c.IndustryCode
});
Okay, I can't see why you'd want to select sector_code when you already know it, but I think you want this:
var query = from company in Companies
join sector in Sectors
on company.SectorCode equals sector.SectorCode
join industry in DistributionSectorIndustry
on sector.SectorCode equals industry.SectorCode
where industry.Service == "numerical"
select new {
company.EquityCusip,
company.CompanyName,
company.PrimaryExchange,
company.SectorCode,
sector.Description,
industry.IndustryCode
};
Notes:
I've changed it into a query expression as that's a much more readable way of expressing a query like this.
Although the "where" clause comes after the join, assuming this is a LINQ to SQL or Entity Framework query, it shouldn't make any difference
I've lengthened the range variable names for clarity
I've converted your other names into conventional .NET names; you can do this too in your model
For 4 Tables
var query = CurrencyDeposits
.Join(Customers, cd => cd.CustomerId, cus => cus.Id, (cd, cus)
=> new { CurrencyDeposit = cd, Customer = cus })
.Join(Currencies, x => x.CurrencyDeposit.CurrencyId, cr => cr.Id, (x, cr)
=> new { x.CurrencyDeposit, x.Customer, Currency = cr })
.Join(Banks, x => x.CurrencyDeposit.BankId, bn => bn.Id, (x, bn)
=> new { x.CurrencyDeposit, x.Customer, x.Currency, Bank = bn})
.Select(s => new {
s.CurrencyDeposit.Id,
s.Customer.NameSurname,
s.Currency.Code,
s.Bank.BankName,
s.CurrencyDeposit.RequesCode
});
Try something like this...
var myList = ({from a in Companies
join b in Sectors on a.Sector_code equals b.Sector_code
join c in Distribution on b.distribution_code equals a.distribution_code
select new {...});

LINQ : Left Join And Right Join with a double selection

I am looking for a solution to have all the content of the table PART (by adding a right/left join I suppose) in the following LINQ query :
var query = (from p in db.PARTS
join oc in db.OUTPUT_CONTROLS on p.id equals oc.partid
join f in db.FCT on p.fct equals f.id
select new
{ p.id, p.plant, p.unit, p.type, p.num, f.name, oc.datetime, oc.ncr }
into x
group x by new
{ x.id, x.plant, x.unit, x.type, x.num, x.name }
into g
select new
{ g.Key.id, g.Key.plant, g.Key.unit, g.Key.type, g.Key.num, g.Key.name, startdate = g.Min(oc => oc.datetime), endate = g.Max(oc => oc.datetime), sumncr = g.Sum(oc => oc.ncr) })
.OrderByDescending(oc => oc.startdate);
Thanks
I found the solution on my own thanks to this post : LINQ Left Join And Right Join
The solution :
var query = (from p in db.PARTS
join oc in db.OUTPUT_CONTROLS on p.id equals oc.partid into joined
join f in db.FCT on p.fct equals f.id
from j in joined.DefaultIfEmpty()
select new
{ p.id, p.plant, p.unit, p.type, p.num, f.name, j.datetime, j.ncr } into x
group x by new { x.id, x.plant, x.unit, x.type, x.num, x.name } into g
select new { g.Key.id, g.Key.plant, g.Key.unit, g.Key.type, g.Key.num, g.Key.name, startdate = g.Min(oc => oc.datetime), endate = g.Max(oc => oc.datetime), sumncr = g.Sum(oc => oc.ncr) })
.OrderByDescending(oc => oc.startdate);
If you have a SQL where you see a join followed by a GroupJoin, consider using the LINQ GroupJoin.
Quite often you'll see this in situations where you want "Schools with their Students", "Customers with their Orders", "Zoos with their Animals"
It seems that you have 3 tables: Parts, OutputControls and Fcts.
Every Part has zero or more OutputControls, and every OutputControl belongs to exactly one Part, using foreign key PartId: a straightforward one-to-many relation
A Part has a foreign key FctId, that points to the Fct of the part.
You want (some properties of) the Parts, with their OutputControls and its Fct
var result = parts.GroupJoin(outputControls, // GroupJoin Parts and OutputControls
part => part.Id, // from every part take the Id
outputControl => outputControl.PartId, // from every outputControl take the PartId
// result selector: when these Ids match,
// use the part and all its matching outputControls to make one new object:
(part, outputControlsOfThisPart) => new
{
// select the part properties you plan to use:
Id = part.id,
Plant = part.plant,
Unit = part.unit
// the output controls of this part:
OutputControls = outputControlsOfThisPart.Select(outputControl => new
{
// again, select only the output control properties you plan to use
Id = outputControl.Id,
Name = outputControl.Name,
...
})
.ToList(),
// For the Fct, take the Fct with Id equal to Part.FctId
Fct = Fcts.Where(fct => fct.Id == part.Fct)
.Select(fct => new
{
// select only the Fct properties you plan to use
Id = fct.Id,
Name = fct.Name,
...
})
// expect only one such Fct
.FirstOrDefault(),
});

Categories

Resources