Невозможно преобразовать SQL-запрос в запрос LINQ для Left Outer Join

Проблема:

Я пытаюсь преобразовать один из моих запросов Sql в linq, но я не могу получить желаемый результат, который мне нужен. Может ли кто-нибудь предложить мне, что я должен делать?

SQL-запрос:

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 Я использую:

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?

Что я делаю неправильно?

Любое предложение получить желаемый запрос, например Sql в Linq?

Таблица тегов активов:

enter image description here

Таблица проблем:

enter image description here

Таблица возврата:

enter image description here

Желаемый результат:

enter image description here

Ответ 1

Вам нужно сделать следующее:

 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();

Ответ 2

Вам нужно удалить .AsEnumerable(), потому что вы хотите, чтобы ваш запрос был переведен на sql. Прямо сейчас он будет использовать linq-to-objects, и если вы используете левое соединение с linq-to-object, вам нужно проверить исключения для нулевой ссылки. rt может быть нулевым, поэтому rt.RequestStatus генерирует исключение.

* Я полагаю, что rt должен быть r в вашем примере

Вы не можете проецировать существующий объект, поэтому вам нужно изменить свой выбор на:

select new PocoClass
{
  model1=at 
}

//New class definition
public PocoClass
{
  public AssetTagging model1 { get; set; }
}

Ответ 3

Попробуйте следующее. Я предполагаю, что вам все еще нужны случаи, когда r равно null, если r не является нулевым и статус запроса = одобрен.

Вы должны проверить, чтобы проверить r!= null перед проверкой статуса запроса, и вам все равно нужно включить, когда r равно null, чтобы получить полный набор результатов. Я не тестировал это, но это должно поставить вас в правильном направлении.

Удачи.

  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();

Ответ 4

попробуйте следующее:

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"

Просто сделайте два раза оставшееся внешнее соединение, а затем выполните фильтрацию при условии.

Также сначала рассмотрите this msdn статью о левом внешнем соединении с использованием linq.

Ответ 5

Я знаю, что это не совсем то, о чем вы просили, но в любом случае это может быть полезно.

Если у вас есть доступ к базе данных для выполнения SQL-запросов, я бы предложил создать представление. Затем вы можете отбросить представление в свой DBML файл так же, как и с таблицей, и иметь гораздо более простые выражения Linq в коде С#.

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')

Ответ 6

Вот полный запрос

  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();