left outer join 3 tables in linq to sql - linq

I was trying to write a query in linq where I join 3 tabels and fill in the null values with the string "ANY" but this is not happening need some help please i am new at this.
I tried doing something like this...
var results = from user in allusers
join building in allbuildings where building.buildingid equals user.buildingid
into BuildingAndUsers.FirstorDefault(new allbuildings{BuildingName="ANY" BuildingID=0})
from blah in BuildingAndUsers
join Site in AllSites where ....

Something like:
var results =
from user in allusers
join building in allbuildings on building.buildingid equals user.buildingid
into BuildingAndUsers
from buildingAndUser in BuildingAndUsers.DefaultIfEmpty(new allbuildings { BuildingName="ANY", BuildingID=0 })
join Site in AllSites on ....
into BuildingAndUsersAndSites
from buildingAndUsersAndSite in BuildingAndUsersAndSites.DefaultIfEmpty()
select ...

Related

How to get TOP 1 result from a LINQ left join without APPLY

I have a master table and I intend to use a left join with LINQ.
Unfortunately the left join multiplies the result (I need only a top 1 result from that).
Here comes the problem: my query should have SQL 8 conformance.
So when I use the following query:
var query = from user in context.User
join group in context.Groups on user.ID equals group.GroupID into groupJoin
from subGroup in groupJoin.Take(1).DefaultIfEmpty()
select new
{
Name = user.Name,
GroupName = subGroup!=null ? subGroup.Name : null
};
I get this exception:
The execution of this query requires the APPLY operator, which is not
supported in versions of SQL Server earlier than SQL Server 2005.
How could I replace my query to have SQL8 conformance?
Unfortunately I have no EF4 to test (it does the trick in the latest EF6), but you can try to force usage of a SQL subquery expression(s) like this:
var query = from user in context.User
select new
{
Name = user.Name,
GroupName = (from g in context.Groups where g.GroupId == user.Id select g.Name).FirstOrDefault()
};
Used your linq-query without take(1) and after that use next code:
query = query.Take(1);

Linq left outer group by, then left outer the group

I've this query that i'm trying to put as linq:
select *
from stuff
inner join stuffowner so on so.stuffID = stuff.stuffID
left outer join (select min(loanId) as loanId, stuffownerId from loan
where userid = 1 and status <> 2 group by stuffownerId) t on t.stuffownerid = so.stuffownerid
left outer join loan on t.LoanId = loan.LoanId
when this is done, I would like to do a linq Group by to have Stuff has key, then stuffowners + Loan as value.
I can't seem to get to a nice query without sub query (hence the double left outer).
So basically what my query does, is for each stuff I've in my database, bring the owners, and then i want to bring the first loan a user has made on that stuff.
I've tried various linq:
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tLoan in Loans on so.StuffOwnerId equals tLoan.StuffOwnerId into tmpJoin
from tTmpJoin in tmpJoin.DefaultIfEmpty()
group tTmpJoin by new {stuff} into grouped
select new {grouped, fluk = (int?)grouped.Max(w=> w.Status )}
This is not good because if I don't get stuff owner and on top of that it seems to generate a lot of queries (LinqPad)
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tmpLoan in
(from tLoan in Loans group tLoan by tLoan.StuffOwnerId into g
select new {StuffOwnerId = g.Key, loanid = (from t2 in g select t2.LoanId).Max()})
on so.StuffOwnerId equals tmpLoan.StuffOwnerId
into tmptmp from tMaxLoan in tmptmp.DefaultIfEmpty()
select new {stuff, so, tmptmp}
Seems to generate a lot of subqueries as well.
I've tried the let keyworkd with:
from tstuffOwner in StuffOwners
let tloan = Loans.Where(p2 => tstuffOwner.StuffOwnerId == p2.StuffOwnerId).FirstOrDefault()
select new { qsdq = tstuffOwner, qsdsq= (int?) tloan.Status, kwk= (int?) tloan.UserId, kiwk= tloan.ReturnDate }
but the more info i get from tLoan, the longer the query gets with more subqueries
What would be the best way to achieve this?
Thanks

How to return values from query when joining multiple tables in Linq?

I have a Linq queries that have tables join and couple of tables inner join together. Sometimes I got an error from the query when table is empty. What I trying to do is I am tryting to get a value from table even if other table is empty.
Thanks in Advance.
You need to do left join
Assuming left join between customer and order table.
var query =
from customer in dc.Customers
from order
in dc.Orders
.Where(o => customer.CustomerId == o.CustomerId)
.DefaultIfEmpty()
select new { Customer = customer, Order = order }
Also refer below link
http://forums.asp.net/t/1792428.aspx/1

Linq to entities Left Join

I want to achieve the following in Linq to Entities:
Get all Enquires that have no Application or the Application has a status != 4 (Completed)
select e.*
from Enquiry enq
left outer join Application app
on enq.enquiryid = app.enquiryid
where app.Status <> 4 or app.enquiryid is null
Has anyone done this before without using DefaultIfEmpty(), which is not supported by Linq to Entities?
I'm trying to add a filter to an IQueryable query like this:
IQueryable<Enquiry> query = Context.EnquirySet;
query = (from e in query
where e.Applications.DefaultIfEmpty()
.Where(app=>app.Status != 4).Count() >= 1
select e);
Thanks
Mark
In EF 4.0+, LEFT JOIN syntax is a little different and presents a crazy quirk:
var query = from c1 in db.Category
join c2 in db.Category on c1.CategoryID equals c2.ParentCategoryID
into ChildCategory
from cc in ChildCategory.DefaultIfEmpty()
select new CategoryObject
{
CategoryID = c1.CategoryID,
ChildName = cc.CategoryName
}
If you capture the execution of this query in SQL Server Profiler, you will see that it does indeed perform a LEFT OUTER JOIN. HOWEVER, if you have multiple LEFT JOIN ("Group Join") clauses in your Linq-to-Entity query, I have found that the self-join clause MAY actually execute as in INNER JOIN - EVEN IF THE ABOVE SYNTAX IS USED!
The resolution to that? As crazy and, according to MS, wrong as it sounds, I resolved this by changing the order of the join clauses. If the self-referencing LEFT JOIN clause was the 1st Linq Group Join, SQL Profiler reported an INNER JOIN. If the self-referencing LEFT JOIN clause was the LAST Linq Group Join, SQL Profiler reported an LEFT JOIN.
Do this:
IQueryable<Enquiry> query = Context.EnquirySet;
query = (from e in query
where (!e.Applications.Any())
|| e.Applications.Any(app => app.Status != 4)
select e);
I don't find LINQ's handling of the problem of what would be an "outer join" in SQL "goofy" at all. The key to understanding it is to think in terms of an object graph with nullable properties rather than a tabular result set.
Any() maps to EXISTS in SQL, so it's far more efficient than Count() in some cases.
Thanks guys for your help. I went for this option in the end but your solutions have helped broaden my knowledge.
IQueryable<Enquiry> query = Context.EnquirySet;
query = query.Except(from e in query
from a in e.Applications
where a.Status == 4
select e);
Because of Linq's goofy (read non-standard) way of handling outers, you have to use DefaultIfEmpty().
What you'll do is run your Linq-To-Entities query into two IEnumerables, then LEFT Join them using DefaultIfEmpty(). It may look something like:
IQueryable enq = Enquiry.Select();
IQueryable app = Application.Select();
var x = from e in enq
join a in app on e.enquiryid equals a.enquiryid
into ae
where e.Status != 4
from appEnq in ae.DefaultIfEmpty()
select e.*;
Just because you can't do it with Linq-To-Entities doesn't mean you can't do it with raw Linq.
(Note: before anyone downvotes me ... yes, I know there are more elegant ways to do this. I'm just trying to make it understandable. It's the concept that's important, right?)
Another thing to consider, if you directly reference any properties in your where clause from a left-joined group (using the into syntax) without checking for null, Entity Framework will still convert your LEFT JOIN into an INNER JOIN.
To avoid this, filter on the "from x in leftJoinedExtent" part of your query like so:
var y = from parent in thing
join child in subthing on parent.ID equals child.ParentID into childTemp
from childLJ in childTemp.Where(c => c.Visible == true).DefaultIfEmpty()
where parent.ID == 123
select new {
ParentID = parent.ID,
ChildID = childLJ.ID
};
ChildID in the anonymous type will be a nullable type and the query this generates will be a LEFT JOIN.

Linq To Entity Framework selecting whole tables

I have the following Linq statement:
(from order in Orders.AsEnumerable()
join component in Components.AsEnumerable()
on order.ORDER_ID equals component.ORDER_ID
join detail in Detailss.AsEnumerable()
on component.RESULT_ID equals detail.RESULT_ID
where orderRestrict.ORDER_MNEMONIC == "MyOrderText"
select new
{
Mnemonic = detail.TEST_MNEMONIC,
OrderID = component.ORDER_ID,
SeqNumber = component.SEQ_NUM
}).ToList()
I expect this to put out the following query:
select *
from Orders ord (NoLock)
join Component comp (NoLock)
on ord .ORDER_ID = comp.ORDER_ID
join Details detail (NoLock)
on comp.RESULT_TEST_NUM = detail .RESULT_TEST_NUM
where res.ORDER_MNEMONIC = 'MyOrderText'
but instead I get 3 seperate queries that select all rows from the tables. I am guessing that Linq is then filtering the values because I do get the correct values in the end.
The problem is that it takes WAY WAY too long because it is pulling down all the rows from all three tables.
Any ideas how I can fix that?
Remove the .AsEnumerable()s from the query as these are preventing the entire query being evaluated on the server.

Resources