4

Problem Statement:

I'm trying to convert one of my Sql to linq query, but I'm unable to get the desired output which i need. Can anyone suggest me what i should do?

SQL Query:

SELECT AssetTagging.AssetID, AssetTagging.AssetDescription, [Return].RequestStatus
FROM  AssetTagging
LEFT OUTER JOIN [Return] ON AssetTagging.AssetID = [Return].AssetID
LEFT OUTER JOIN Issue ON AssetTagging.AssetID = Issue.AssetID
WHERE (Issue.AssetID IS NULL) OR ([Return].RequestStatus = 'Approved')

Linq Query I'm using:

var result = (from at in db.AssetTagging.AsEnumerable()
                  join r in db.Return on at.AssetID equals r.AssetID
                  orderby at.AssetID
                  where !db.Issue.Any(issue=>issue.AssetID==at.AssetID) || r.RequestStatus=="Approved"
                  select new globalTestModel
                  {
                    model1=at
                  }).ToList();


//I know that in Linq query I'm using Inner join instead of Left Join,but i'm getting error if i use left join instead of inner join?

What am I doing wrong??

Any suggestion to get desired query like Sql in Linq?

Asset Tag table:

enter image description here

Issue table:

enter image description here

Return table:

enter image description here

Desired Output :

enter image description here

Vishal I P
  • 2,005
  • 4
  • 24
  • 41
  • possible duplicate of [LINQ to SQL Left Outer Join](http://stackoverflow.com/questions/700523/linq-to-sql-left-outer-join) – vittore Feb 06 '15 at 15:05
  • @vittore:But the link what you shared i referred earlier to convert my inner join to left outer join but it is giving error like object reference not set to an instance of an object.I have changed it as `join r in db.Return on at.AssetID equals r.AssetID into t from rt in t.DefaultIfEmpty()` and in where condition `rt.RequestStatus=="Approved"`.I think where condition is giving error – Vishal I P Feb 06 '15 at 15:18
  • I don't see where you refer to the link commented. Example from the linked topic tells you to use `join r in db.Return on at.AssetID equals r.AssetID into joinedReturns`. – vittore Feb 06 '15 at 16:38
  • Can you be more specific about what the issue is? What error are you receiving or how is the data not looking the way you're expecting? It's possible that the issue is simply the fact that your `orderby` is before your `where`, so more context would be very useful. – kevin.groat Feb 18 '15 at 07:14

6 Answers6

2

You need to remove .AsEnumerable(), because you want your query to be translated to sql. Right now it would be using linq-to-objects and if you are using a left join with linq-to-object you need to check for null reference exceptions. rt could be null, so rt.RequestStatus would throw an exception.

*I believe rt should be r in your example

You can't project to an existing entity, so you need to change your select to:

select new PocoClass
{
  model1=at 
}

//New class definition
public PocoClass
{
  public AssetTagging model1 { get; set; }
}
Aducci
  • 26,101
  • 8
  • 63
  • 67
  • Yes that is r not rt,i have updated my question could you please check it again.I need it as .AsEnumerable because I'm binding Enumerable model to my View. – Vishal I P Feb 06 '15 at 14:56
  • Hi,I checked .AsEnumerable is not the problem.Can u help me in using Left Join between Asset Tagging and return table instead of inner join.Instead of Inner Join for Left Join I have used `join r in db.Return on at.AssetID equals r.AssetID into t from rt in t.DefaultIfEmpty()` , but it is giving error – Vishal I P Feb 06 '15 at 15:06
  • It is giving error as object reference not set to an instance of object only for left outer join not for inner join.What's wrong?? – Vishal I P Feb 06 '15 at 15:24
  • @VishalIPatil - `AsEnumerable()` is the problem. What happens if you remove it? – Aducci Feb 06 '15 at 16:00
  • If I remove AsEnumerable(),i'm getting exception as `Unable to create a constant value of type 'globalTestModel'. Only primitive types or enumeration types are supported in this context`.globalTestModel is a collection of models. – Vishal I P Feb 09 '15 at 07:23
1

Try the following I am assuming that you still want the cases where r is null unless r is not null and request status = approved.

You have to check to verify r!=null before checking the request status and you will still need to include when r is null to get the complete result set. I haven't tested this, but this should put you in the right direction.

Good luck.

  var result = (from at in db.AssetTagging
               join r in db.Return.DefaultIfEmpty()
               on at.AssetID equals r.AssetID
               join i in db.Issue.DefaultIfEmpty()
               on  at.AssetID equals i.AssetID
               where 
               (r == null || (r!=null && r.RequestStatus == "Approved"))
               || i == null
               select new {
                at.AssetID,
                at.AssetDescription,
                IssueID = (i!=null) ? i.IssueID : null),
                ReturnID = (r!=null) ? r.ReturnID: null),
                ReturnStatus = (r!=null) 
                     ? r.ReturnStatus 
                     : null}).ToList();
C Tierney
  • 1,061
  • 1
  • 8
  • 14
1

You need to do like this:

 var result = from at in db.AssetTagging
              join r in db.Returns on at.AssetID equals r.AssetID into a
              from returns into a.DefaultIfEmpty()
              join i in db.Issues on at.AssetID equals I.AssetID into b
              from issues into b.DefaultIfEmpty()
              where issues.AssetID != null || returns.RequestStatus == "Approved"
              select new
                    {
                      AssetID = at.AssetID,
                      AssetDescription = at.AssetDescription,
                      Status = returns != null ? returns.RequestStatus : null
                    }.ToList();
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
1

try like following:

from at in db.AssetTagging
join r in db.Return on at.AssetID equals r.AssetID into res1
from atr in res1.DefaultIfEmpty()
join  i in db.Issues on i.AssetID==at.AssetID into res2
from obj in res2.DefaultIfEmpty()
select at
where i.AssetID == null || r.RequestStatus equals "Approved"

Just make two times left outer join and then do filter on where condition.

Also have first look at this msdn article about left outer join using linq.

Jenish Rabadiya
  • 6,708
  • 6
  • 33
  • 62
1

I know this isn't exactly what you've asked for, but it might be useful anyway.

If you have access to the database to execute SQL queries, I would suggest creating a view. You can then drop the view into your DBML file the same way as you would with a table, and have much simpler Linq expressions in your C# code.

CREATE VIEW [Asset_Issue_Return_Joined] AS
SELECT AssetTagging.AssetID, AssetTagging.AssetDescription, [Return].RequestStatus
FROM  AssetTagging
LEFT OUTER JOIN [Return] ON AssetTagging.AssetID = [Return].AssetID
LEFT OUTER JOIN Issue ON AssetTagging.AssetID = Issue.AssetID
WHERE (Issue.AssetID IS NULL) OR ([Return].RequestStatus = 'Approved')
Brett
  • 843
  • 1
  • 7
  • 18
0

Here is the complete query

  var result = (from assetTagging in db.AssetTagging
                join return0 in db.Return on assetTagging.AssetID equals return0.AssetID into returns
                from return0 in returns.DefaultIfEmpty()
                join issue in db.Issue on assetTagging.AssetID equals issue.AssetID into issues
                from issue in issues.DefaultIfEmpty()
                where issue.AssetID == null || return0.RequestStatus == "Approved"
                select new
                {
                   assetTagging.AssetID,
                   assetTagging.AssetDescription,
                   return0.RequestStatus
                }).ToList();
Tinu
  • 197
  • 2
  • 9