How do I do a left outer join in LINQ? - linq

Can anybody explain in detail how to implement a left outer join in LINQ?

The key aspect here is DefaultIfEmpty()
Take a look at the following article to get a basic understanding. The example here is demonstrated for LINQ to SQL.
http://smehrozalam.wordpress.com/2009/06/10/c-left-outer-joins-with-linq/
If you are looking for LINQ to Objects example, then have a look at this
http://www.hookedonlinq.com/OuterJoinSample.ashx

Related

Cross-Join Syntax in Entity Framework / IQueryable

I'm trying to deepen my education about IQueryable custom providers and expression trees. I'm interested in custom parsing a cross-join (viz. SelectMany), and I'm trying to understand if that is exactly what EF is doing when it handles this:
var infoQuery =
from cust in db.Customers
from ord in cust.Orders
where cust.City == "London"
select ord;
Allegedly EF can handle cross joins, though the syntax in that link does not look right to me. Then I found a link with the title "Cross Product Queries" for EF. The syntax looks "correct," but the article itself speaks as if these are normal inner joins rather than cross joins.
Indeed, the code snippet above comes from that last article - and leaves me wondering if EF simply says "I know how these two entities are related, so I will form the inner-join automatically."
What is the real story with EF and this alleged "cross join" sample?
footnote
As I try to build my own IQueryable LINQ provider, the educational goal I've set for myself is to make my own query context for the code snippet above, so that when ToList() is called on the query:
A Console.WriteLine() is automatically fired that prints "This is a cross join of:Customer and Order
The == operator is magically converted into a != before the query is fully interpreted (by an ExpressionVisitor perhaps, not sure).
If someone knows of articles or has snippets of code that would speed my educational goal, please do share! :)
Look closely at the syntax:
from cust in db.Customers
from ord in cust.Orders // cust.
select ...
Because of cust.Orders this is a regular inner join. It's even the preferred way to do a join, because it is far more succinct than the regular join statement.
I don't understand the title of this "Cross-Product Queries" article. Firstly, because as far as I know "cross product" applies to three-dimensional vectors not relational algebra. Secondly, because there is not a single cross join in the examples, only inner joins. Maybe what they're trying to say is that the above syntax looks like a cross join? But it isn't, so it's only confusing to use the word so prominently in the title.
This code snippet
from cust in db.Customers
from ord in db.Orders // db.
select ...
is a true cross join (or Cartesian product). If there are n customers and m orders the result set contains n * m rows. Hardly useful with orders and customers, but it can be useful to get all combinations of elements in two sequences. This construct can also be useful if you want to join but also need a second condition in the join, like
from cust in db.Customers
from ord in db.Orders
where cust.CustomerId == ord.CustomerId && ord.OrderDate > DateTime.Today
Which effectively turns it into an inner join. Maybe not the best example, but there are cases where this comes in handy. It is not supported in the join - on - equals syntax.

Bind Distinct LINQ query to Telerik grid

I'm trying to bind a LINQ query that has a Distinct() in it and bind it to a Telerik Grid (this is the Telerik grid still, haven't converted to Kendo yet). I've tried adding AsQueryable() to it also, but still getting a "Specified method is not supported exception."
My query looks like this:
var rewardTypes = (from type in _rewardTypeRepository.GetAll()
from vo in type.ValidOutlets
join ot in _outletRepository.GetAll()
on vo.Outlet.Id equals ot.Id
where userOutletIds.Contains(ot.Id)
select vo.RewardType).Distinct().AsQueryable();
Any ideas or guidance on this would be greatly appreciated.
Thank you,
Matt
Using .Distinct() or IQueryable<T> just lazy loads the collection of data, meaning it's not actually enumerated yet.
Try converting it to a List<T>.
var rewardTypes = (from type in _rewardTypeRepository.GetAll()
from vo in type.ValidOutlets
join ot in _outletRepository.GetAll()
on vo.Outlet.Id equals ot.Id
where userOutletIds.Contains(ot.Id)
select vo.RewardType).ToList();
If you want to remain "light" and not enumerate every item in a potentially large collection, I suggest using the .Skip() and .Take() methods to paginate through results at your convenience. Both those methods work against an IQueryable<T> collection.

Oracle query with multiple tables

I am trying to display volunteer information with duty and what performance is allocated.
I want to display this information. However, when I run the query, it did not gather the different date from same performance. And also availability_date is mixed up. Is it right query for it? I am not sure it is right query.
Could you give me some feedback for me?
Thanks.
Query is here.
SELECT Production.name, performance.performance_date, volunteer_duty.availability_date, customer.name "Customer volunteer", volunteer.volunteerid, membership.name "Member volunteer", membership.membershipid
FROM Customer, Membership, Volunteer, volunteer_duty, duty, performance_duty, performance, production
WHERE
Customer.customerId (+) = Membership.customerId AND
Membership.membershipId = Volunteer.membershipId AND
volunteer.volunteerid = volunteer_duty.volunteerid AND
duty.dutyid = volunteer_duty.dutyid AND
volunteer_duty.dutyId = performance_duty.dutyId AND
volunteer_duty.volunteerId = performance_duty.volunteerId AND
performance_duty.performanceId = performance.performanceId AND
Performance.productionId = production.productionId
--Added image--
Result:
The query seems reasonable, in terms of it having what appear to be the appropriate join conditions between all the tables. It's not clear to me what issue you are having with the results; it might help if you explained in more detail and/or showed a relevant subset of the data.
However, since you say there is some issue related to availability_date, my first thought is that you want to have some condition on that column, to ensure that a volunteer is available for a given duty on the date of a given performance. This might mean simply adding volunteer_duty.availability_date = performance.performance_date to the query conditions.
My more general recommendation is to start writing the query from scratch, adding one table at a time, and using ANSI join syntax. This will make it clearer which conditions are related to which joins, and if you add one table at a time hopefully you will see the point at which the results are going wrong.
For instance, I'd probably start with this:
SELECT production.name, performance.performance_date
FROM production
JOIN performance ON production.productionid = performance.productionid
If that gives results that make sense, then I would go on to add a join to performance_duty and run that query. Et cetera.
I suggest that you explicitly write JOINS, instead of using the WHERE-Syntax.
Using INNER JOINs the query you are describing, could look like:
SELECT *
FROM volunteer v
INNER JOIN volunteer_duty vd ON(v.volunteerId = vd.colunteerId)
INNER JOIN performance_duty pd ON(vd.dutyId = pd.dutyId AND vd.volunteerId = pd.colunteerId)
INNER JOIN performance p ON (pd.performanceId = p.performanceId)

How do i get an inner join in a WCF Data Service

Lets say i have 2 tables, table1 and table2, with a shared key "id"
if i want an inner join of those two tables using sql, i'd do something like
select id, x, y, z
from table1
inner join table2
on table1.id = table2.id
I now get rows in table 1 that only intersect occur in table 2.
how do i get the equivalent in wcf data service/odata linq syntax?
i'm expecting something like:
var q = (from t in svc.Table1.Expand("Table2")
where t.Table2.Any()
select t) as DataServiceQuery<Table1>;
but that gets me an exception about Any().
I've tried .Join and that isn't supported either.
I've tried .Count and that fails too.
.Intersect looks like it only takes another enumerable, so that doesn't look like what i want...
i think i'm missing something really obvious or simple...
Edit: this appears to be a dup of this How do I use OData Expand like a SQL join?
Take a look at the answers to this type of question. The current version of WCF Data Services (OData) does not support joins even if your underlying data contract does (i.e. if you're layering on top of Entity Framework 4 for instance).
The more recent releases of WCF Data Services now include Any/All support. See What's New in WCF Data Services 5.0
Currently the OData protocol (and thus WCF Data Services) doesn't support any/all operations. It also doesn't support arbitrary joins, although some joins can be expressed as navigations.
Your query is currently not supported, but we're looking into adding support for the any/all operations. Take a look at this proposal if that would fulfill your needs:
http://www.odata.org/blog/support-for-any-and-all
Is WCF in play here? To link two objects from two tables/lists, I'd do this:
var result =
from o1 in Table1
join o2 in Table2 on o2.id equals o1.id

Outer Joins with Subsonic 3.0

Does anyone know of a way to do a left outer join with SubSonic 3.0 or another way to approach this problem? What I am trying to accomplish is that I have one table for departments and another table for divisions. A department can have multiple divisions. I need to display a list of departments with the divisions it contains. Getting back a collection of departments which each contain a collection of divisions would be ideal, but I would take a flattened result table too.
Using the LINQ syntax seems to be broken (I am new to LINQ though and may be using it wrong), for example this throws an ArgumentException error:
var allDepartments = from div in Division.All()
join dept in Department.All() on div.DepartmentId equals dept.Id into divdept
select divdept;
So I figured I could fall back to using the SubSonic query syntax. This code however generates an INNER JOIN instead of an OUTER JOIN:
List<Department> allDepartments = new Select()
.From<Department>()
.LeftOuterJoin<Division>(DepartmentsTable.IdColumn, DivisionsTable.DepartmentIdColumn)
.ExecuteTypedList<Department>();
Any help would be appreciated. I am not having much luck with SubSonic 3. I really enjoyed using SubSonic 2 and may go back to that if I can't figure out something as basic as a left join.
Getting back a collection of departments which each contain a collection of divisions would be ideal
SubSonic does this for you (if you setup your relationships correctly in the database), just select all Departments:
var depts = Model.Department.All();
There will be a property in each item of depts named Divisions, which contains a collection of Division objects.

Resources