I have two tables A and B,which I can outer join with linq. I need a way to find if it is possible to have a boolean along with the query if the outer join has a match. For example, I need a boolean to be true if a record is present in tableA and not in tableB. This can be done in SQL using IF, I was wondering if there was something similar in Linq
var result = from a in tableA
join b in tableB on a.Id equals b.userId into group1
from g1 in group1.DefaultIfEmpty()
select new{id = g1.Id,userId = g1.userId,boolIsPresent =(present in tableA not in tableB)}.ToList();
Currently, you're performing an inner join, not a left outer join, which means only records/objects that exist in both tables are retrieved. thus your bool boolIsPresent would always be true.
edit:
to test if a record is present in tableA and does not have a matching record in tableB just check if g1 != null, i.e:
var result = from a in tableA
join b in tableB on a.Id equals b.userId into group1
from g1 in group1.DefaultIfEmpty()
select new
{
id = g1 != null? g1.Id : enterDefault,
userId = g1 != null? g1.userId : enterDefault,
boolIsPresent = g1 != null
}.ToList();
It will be something like
boolisPresent = b != null
Once you get an Outer join working!
Related
this is a bit confusing for me. I know that left outer joins aren't built in to LINQ natively and that you have to use 'into' and 'DefaultIfEmpty()', but I have a bit of a complex SQL query.
The query:
SELECT * FROM TableA as a
LEFT OUTER JOIN TableB as b
on a.ID = b.ID and a.StatusOne = 1 AND b.StatusOne = 1 AND (a.StatusTwo != 1 OR b.StatusTwo!= 1)
LEFT OUTER JOIN TableC as c
on a.ID = c.ID AND a.StatusOne = 1 AND c.StatusOne = 1 AND (a.StatusTwo != 1 OR c.StatusTwo != 1)
WHERE
a.ID = 99999 AND (b.ID is not null OR c.ID is not null)
I'm not even really sure where to begin on this. If someone could help me out I would appreciate it immensely.
I am giving you the idea behind, I didn't tested the code, but to join two tables based on different fields, your join should have a anonymous type to compare.
var one = 1
from a in tableA
join b in tableB on new { a.ID, b.StatusOne } equals new { b.ID, one} into ab
But in your case you have more than one condition, so before calling DefaultIsEmpty, you should check the latest condition
from a in tableA
join b in tableB on new { a.ID, b.StatusOne } equals new { b.ID, one} into ab
from ab in ab.Where(x => x.a.StatusTwo != 1 || x.b.StatusTwo != one).DefaultIfEmpty()
Then the other outer join follows the same pattern and you need to make a final join. A good way to start is downloading the LinqPad and see which lambda expression it generates for your query, and you can take it from there. You can optimize it later but you will get the idea behind the generation. Hope this helps
I have a list and two tables. (This is a very simplified version of the actual schema, but should work for the question)
List_A
FPI
1
2
3
4
Table_B
FPI_______NI
2_________1
4_________2
Table_C
NI_______Name
1_________x
2_________y
My linq query:
(from a in List_A
join b in Table_B on a.FPI equals b.FPI into ab
from b in ab.DefaultIfEmpty()
join c in Table_C on b.FI equals c.FI into bc
from c in bc.DefaultIfEmpty()
select new {
FPI = a.FPI,
Name = c?.Name}).ToList();
this code throws an exception that Object reference not set to an instance of an object..
After a lot of trial and experiment, I have reached to a conclusion that in the second join when i'm doing b.FI equals c.FI, at that time it is failing for the entries for which there is no value in the Table_B.
The expected output of the query should be
ABC
FPI____NI___Name
1_____null__null
2_____1_____x
3_____null__null
4_____2_____y
I'm not sure why this error is coming and what would be the best solution for this problem.
Your query would be perfectly valid if it was a LINQ to Entities query translated to SQL.
However, since the root of the query is List_A which is not a IQueryable, the whole query executes in LINQ to Objects context, where you are supposed to perform null checks on right side variable of the left outer join anywhere, including further join conditions.
So the simple fix would be using
join c in Table_C on b?.FI equals c.FI into bc
However, note that the query is highly inefficient. Since it is resolved to Enumerable methods, the whole Table_B and Table_C will be read in memory and then joined.
A better approach would be to separate the db and in memory queries:
var dbQuery =
from b in Table_B
join c in Table_C on b.FI equals c.FI into bc
from c in bc.DefaultIfEmpty()
select new { b.FPI, c.Name };
var query =
from a in List_A
join bc in dbQuery on a.FPI equals bc.FPI into abc
from bc in abc.DefaultIfEmpty()
select new
{
FPI = a.FPI,
Name = bc?.Name
};
var result = query.ToList();
You can try
var list=(from a in Table_A
join b in Table_B on a.FPI equals b.FPI into ab
from b in ab.ToList()
join c in Table_C on b.NI equals c.NI into bc
from c in bc.DefaultIfEmpty()
select new {
FPI = a.FPI,
Name = c.Name}).ToList();
Update
var list = (from a in Table_A
join b in Table_B on a.FPI equals b.FPI into ab
from b in ab.DefaultIfEmpty()
join c in Table_C on b == null ? 0 : b.NI equals c.NI into bc
from c in bc.DefaultIfEmpty()
select new
{
FBI = a.FPI,
NI = c != null ? c.NI : null,//if NI is nullable
//NI = c != null ? c.NI : 0,//if NI is not nullable
Name = c!=null?c.Name:null
}).ToList();
I have 2 inner joins (3 tables) but I don't know and I find it hard to implement my research about outer join in LINQ. How do I change the last inner join to outer join, such that column will still join even if the column (Role) is null?
Here's an existing SQL version of this which I want to convert to LINQ:
SELECT dbo.EmployeeAccess.id, dbo.EmployeeAccess.EmpNo, dbo.EmployeeAccess.RoleID, dbo.EmployeeAccess.Active, dbo.EmployeeAccessLevel.Role,
dbo.View_HCM.LNameByFName
FROM dbo.EmployeeAccess LEFT OUTER JOIN
dbo.EmployeeAccessLevel ON dbo.EmployeeAccess.RoleID = dbo.EmployeeAccessLevel.id INNER JOIN
dbo.View_HCM ON dbo.EmployeeAccess.EmpNo = dbo.View_HCM.EmpNo
LINQ I now have with 2 inner joins:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
}
Linq's outer join syntax uses 2 parts. First an into then DefaultIfEmpty
In your case, an outer join might look like this:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
from subjoin in outer_join.DefaultIfEmpty()
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
There are many tutorials on how to create the outer join in LINQ.
Hi i am trying to join two tables in c#. the join code is given below. The problem is that when there is null value for tourid in tb_abc then in will not include that row from tb_abc in the list.
return (from p in context.tb_abc
from o in context.tb_Second
where o.id==p.tourId
where p.driverId == driverId
select new abcBean
{
id=p.id,
name=o.name
}).ToList<abcBean>();
Can anyone tell me what i am doing wrong
You are not doing an inner join in that query. You are doing a cross join, its where you have two tables and join each record to every other record.
If you want to include rows that return null on one of the constraints you need a left outer join.
return (from p in tb_abc
join o in tb_Second on p.tourId equals o.id into po
where p.driverId == driverId
from subpo in po.DefaultIfEmpty()
select new abcBean
{
id=p.id,
name=(subpo == null ? String.Empty : subpo.Name)
}).ToList();
Consider these two sql statements:
The first a cross join:
select id, name
from tb_abc o,
tb_Second p
where
o.id = p.tourID
and p.driverID = #driverID
The second a left outer join:
select id, name
from tb_abc o
LEFT OUTER JOIN tb_Second p on o.id = p.tourID
where
p.driverId = #driverID
The second will give you one set of the records, that include the null value of o.id.
The first will give you something of a Cartesian product which you rarely want.
Linq's DefaultIfEmpty() puts the default value (null) into the record if it doesnt find a match for the one side, so it behaves like the left outer join.
you can use left outer join like
return (from p in context.tb_abc
join o in context.tb_Second on o.id==p.tourId into gt
where p.driverId == driverId
from subsecond in gt.DefaultIfEmpty()
select new abcBean
{
id=p.id,
name=(subsecond == null ? String.Empty : subsecond.Name)
}).ToList<abcBean>();
I have a sql query which is to be converted to Linq
Select b.title
from TableA as a
inner join TableB as b
on a.Email=b.Email
where a.Title<>b.Title
the query which i have tried is
var query =from s in TableA
join r in TableB
on r.Email equals s.Email
but not able to replicate the where clause which may include many columns
My requirement is i need to compare the 2 tables on a primary key column and then get the other column values which do not match
You need a "select" at the end of the query, and you need to get the inputs in the right order:
var query = from s in TableA
join r in TableB on s.Email equals r.Email
where s.Title != r.Title
select s.Title;
For multiple columns, use an anonymous type:
var query = from s in TableA
join r in TableB
on new { s.Email, s.Foo } equals new { r.Email, r.Foo }
where s.Title != r.Title
select s.Title;