Linq left outer join with multiple condition - linq

I am new to Linq. I am trying to query some data in MS SQL.
Here is my statement:
select * from booking
left outer join carpark
on booking.bookingId = carpark.bookingId
where userID = 5 and status = 'CL'
When I run this in MS SQL, I get the expected result. How can I do this in Linq?
Thank you for your help.

you need this:
var query = (from t1 in tb1
join t2 in tb2 on t1.pKey = t2.tb1pKey into JoinedList
from t2 in JoinedList.DefaultIfEmpty()
where t1.userID == 5 && t1.status == "CL"
select new
{
t1,
t2
})
.ToList();

You can try to do left join this way :
from t1 in tb1
from t2 in tb2.Where(o => o.tb1pKey == t1.pKey).DefaultIfEmpty()
where tb1.userId == 5 && tb1.status == "CL"
select t1;

Usually when people say they want a "left outer join," that's just because they've already converted what they really want into SQL in their head. Usually what they really want is all of the items from table A, and the ability to get the related items from table B if there are any.
Assuming you have your navigation properties set up correctly, this could be as easy as:
var tb1sWithTb2s = context.tb1
.Include(t => t.tb2s) // Include all the tb2 items for each of these.
.Where(t => t.userID == 5 and t.status = "CL");

Related

Inner Join with two equalities inside on clause in LINQ Lambda

I'm trying to convert a Sql query to a Linq Lambda style query. Thought this would be something easy but it turned out not.
SQL Query is as follows;
select distinct t1.ID from table1 t1
inner Join table2 t2on (t2.FromId= t1.Id or t2.ToId= t1.Id)
where t1.TenantId = 12
and t2.wId= 51
All examples I came across are for one clause joins so far. I wrote something like this
actStaList = _db.t1
.Join(_db.t2,
s => s.ID,
wf => wf.ToId,
(s, wf) => new { t1= s, t2= wf }
)
.Where(a => a.t1.Tenant.Guid == _tenantGuid)
.Select (m=>m.t1.ID)
.ToList();
It is obvious this won't work as the sql query above but still it's a start.
Still I can't figure where should I add the second part inside INNER JOIN and Distinct keyword.
One option you have is to use two separate Linq Queries and concat the result(and eliminating duplicates).
var left = t1.Join(t2,
s => s.ID,
wf => wf.ToId,
(s, wf) => new { t1= s, t2= wf }
).Select(x=>x);
var right = t1.Join(t2,
s => s.ID,
wf => wf.FromId,
(s, wf) => new { t1= s, t2= wf }
).Select(x=>x);
var actStaList = left.Concat(right).Select(m=>m.t1.ID)
.Distinct();
Please note I have omitted the Where Clause in the example as in the OP, both Sql version and your attempted Linq version seem to have different conditions. You can add them yourself.
The LINQ Join statement only supports equi-joins. For other types of equality you can't use the Join statement and have to code the equality manually. This is much easier in query syntax:
actStaList = (
from t1 in _db.table1
from t2 in _db.table2
where t2.FromId == t1.Id || t2.ToId == t1.Id
where t1.TenantId == 12 && t2.wId == 51
select t1.ID
).Distinct();
For the record, you can avoid the Distinct statement by executing this as a SQL EXISTS statement:
actStaList =
from t1 in _db.table1
where t1.TenantId == 12
where (from t2 in _db.table2
where t2.wId == 51 && (t2.FromId == t1.Id || t2.ToId == t1.Id)
select t2).Any()
select t1.ID;

LINQ - count from select with join with no group by

Linq is brand new to me so I apologize if this is really stupid.
I am trying to get the count from a multi-table join with where clause, without group by. I've seen examples of group by and will resort to that if need be, but I am wondering if there is a way to avoid it. Is sql my query would look something like this;
SELECT Count(*)
FROM plans p
JOIN organizations o
ON p.org_id = o.org_id
AND o.deleted IS NULL
JOIN orgdata od
ON od.org_id = o.org_id
AND od.active = 1
JOIN orgsys os
ON os.sys_id = od.sys_id
AND os.deleted IS NULL
WHERE p.deleted IS NULL
AND os.name NOT IN ( 'xxxx', 'yyyy', 'zzzz' )
What's the best way to get this?
All you need is to call Count(). You're only counting the number of results. So something like:
var names = new[] { "xxxx", "yyyy", "zzzz" };
var query = from plan in db.Plans
where plan.Deleted == null
join organization in db.Organizations
on plan.OrganizationId equals organization.OrganizationId
where organization.Deleted == null
join orgData in db.OrganizationData
on organization.OrganizationId equals orgData.OrganizationId
where orgData.Active == 1
join os on db.OrganizationSystems
on orgData.SystemId equals os.SystemId
where os.Deleted == null &&
!names.Contains(os.Name)
select 1; // It doesn't matter what you select here
var count = query.Count();

Linq 2 SQL left Join with mono

I cant get the fallowing request working in Mono:
Without joins it would work.
when I only select t1 it also works, but I cant select something from both tables.
I think I want a left join, where I always have entries in t1 and IF the NameOfFile matches FileName then I want to have the tables joined.
Extra Question: When is my query executed? When I run the foreach loop?
var result = (
from t1 in db.Table1
join t2 in db.Table2 on t1.FileName equals t2.NameOfFile
into joinDep
from t3 in joinDep.DefaultIfEmpty ()
select new
{
Time = t1.WriteTime,
Name = t2.NameOfFile
}
)
.OrderByDescending (c => c.Time.Date)
.Take (10);
foreach (var entry in result)
{
Console.WriteLine (entry.Name );
}
Use this:
var query = from t1 in db.Table1
join t2 in db.Table2 on t1.FileName equals t2.NameOfFile into gj
from joinDep in gj.DefaultIfEmpty ()
select new
{
Time = t1.WriteTime,
Name = joinDep.NameOfFile
};
var result = query.OrderByDescending (c => c.Time.Date)
.Take (10);
Yes. Take uses deferred execution.

How to write this LINQ Query in a better way

I have one Linq Query. When I run the query, Only for 10 records its taking 13 seconds to extract the data to the model. I need to know the query which I wrote is good for performance or not. Please guide me what i am doing wrong.
Code
var stocktakelist = (from a in Db.Stocktakes
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = (from admin in Db.AdminAccounts where admin.Id == a.Id select admin.Name).FirstOrDefault(),
CreatedOn = a.CreatedOn,
Status = (from items in Db.Items where items.ItemNo == a.ItemNo select items.ItemStatu.Description).FirstOrDefault(),
Title = (from tit in Db.BibContents where tit.BibId == (from bibs in Db.Items where bibs.ItemNo == a.ItemNo select bibs.BibId).FirstOrDefault() && tit.TagNo == "245" && tit.Sfld == "a" select tit.Value).FirstOrDefault() // This line of Query only makes the performance Issue
}
).ToList();
Thanks
The reason this is so slow is because it is running the 3 inner LINQ statements for every item in the outer LINQ statement.
Using LINQ joins will run only 4 queries and then link them together, which is faster.
To find out how to join, there are plenty of resources on the Internet depending on the type of LINQ you are using.
If you're retrieving this data from a SQL server, perhaps consider doing this intensive work in SQL - this is what SQL was designed for and it's much quicker than .NET. EDIT: As highlighted below, the work is done in SQL if using LINQ to SQL/Entities and using the correct join syntax.
I was trying to create the corresponding query with some joins for practice.
I cannot test it and i'm not 100% sure that this query will you get the result
you are hoping for but maybe at least it will give you a hint on how to write
joins with linq.
from a in Db.Stocktakes
join admin in Db.AdminAccounts
on a.Id equals admin.Id
into adminJoinData
from adminJoinRecord in adminJoinData.DefaultIfEmpty( )
join items in Db.Items
on a.ItemNo equals items.ItemNo
into itemsJoinData
from itemsJoinRecord in itemsJoinData.DefaultIfEmpty( )
join title in Db.BibContents
(
from subQuery in Db.BibContents
where subQuery.TagNo == "245"
where subQuery.Sfld == "a"
select subquery
)
on title.BibId equals itemsJoinRecord.BidId
into titleJoinData
from titleJoinRecord in titleJoinData.DefaultIfEmpty( )
select new ExportStock( )
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = adminJoinRecord.Name,
CreatedOn = a.CreatedOn,
Status = itemsJoinRecord.ImemStatu.Description,
Title = titleJoinRecord.Value
}
As others have said, you should use Left Outer Joins in your LINQ just as you would if writing it in SQL.
Your query above will end up looking roughly like this once converted (this is untested, but gives the basic idea):
var a = from a in Db.Stocktakes
join admin in Db.AdminAccounts on admin.Id equals a.Id into tmpAdmin
from ad in tmpAdmin.DefaultIfEmpty()
join item in Db.Items on item.ItemNo equals a.ItemNo into tmpItem
from it in tmpItem.DefaultIfEmpty()
join title in Db.BibContents on bib.BibId equals items.BibId into tmpTitle
from ti in tmpTitle.DefaultIfEmpty()
where ti.TagNo == "245"
&& ti.Sfld == "a"
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = ad == null ? default(int?) : ad.Id,
CreatedOn = a.CreatedOn,
Status = it == null ? default(string) : it.ItemStatus.Description,
Title = ti == null ? default(string) : ti.Value
};
Using lambda expressions your query will look like this:
Db.Stocktakes
.Join(Db.AdminAccounts, a => a.Id, b => b.Id, (a,b) => new { a, AdminId = b.Name })
.Join(Db.Items, a => a.ItemNo, b => b.ItemNo, (a,b) => new { a, Status = b.ItemStatus.Description, BidId = b.BibId })
.Join(Db.BibContents, a => a.BibId, b => b.BibId, (a,b) => new { a, Value = b.Value, TagNo = b.TagNo, Sfld = b.Sfld })
.Where(a => a.TagNo == "245" && a.Sfld == "a")
.Select(a =>
new ExportStock { Id = a.Id,
ItemNo = a.ItemNo,
AdminId = a.AdminId,
CreatedOn = a.CreatedOn,
Status = a.Status,
Title = a.Value
}
).ToList();

Join statement in Linq to Sql

I need to write Join statment after writing query in linq
example :
var Query = (from Tab in Db.Employees
select Tab)
as i have some cases to perform join operation so
i need to do it on this Query Query.Join(Join with another Table like Department); I need the Syntax
if (DeptID != -1){ Query.Join(Join with table Department where FkDeptID = DeptID); }
Consider the usage of join in the LINQ 'query syntax':
from t1 in db.Table1
join t2 in db.Table2 on t1.field equals t2.field
select new { t1.field2, t2.field3}
Something like this?
var results = (from q in Query
join m in myList on q.SomeID = m.SomeID
select unknown);
Try using this query:
var Query =
from e in Db.Employees
join d in Db.Departments on e.FkDeptID equals d.DeptID into departments
select new
{
Employee = e,
Department = departments.SingleOrDefault(),
};
This works assuming that when e.FkDeptID == -1 that there is no record in the Departments table and in that case Department would be assigned null.
You should never have more than one department for an employee so I've used SingleOrDefault rather than FirstOrDefault.

Resources