Как объединить внутреннее соединение и левое соединение в Entity Framework - PullRequest
7 голосов
/ 11 августа 2011

Я использую DBContext API из EF 4.1. Рассмотрим следующую модель сущностей (A, B, E, D - сущности)

A: AID

B: AID, CID

E: eId, aId

D: eId, cId, Data

То, что я хочу, эквивалентно приведенному ниже SQL-запросу

SELECT
   B.aId,
   B.cId,
   COALESCE(M.Data, [default value])
FROM
   B LEFT OUTER JOIN
   (
      SELECT
         E.aId,
         D.cId,
         D.Data  
      FROM
         E INNER JOIN D ON E.eId = D.eId
   ) M
   ON B.aId = M.aId AND B.cId = M.cId

Это просто оставить соединение на B, E & D, но я обнаружил, что не могу решить вышеупомянутый запрос. Я пробовал linq форму того, что я думаю, будет эквивалентным запросом

// inner join equivalent
var ee = db.E.Join(db.D, e => e.eId, d => d.eId,
    (e, d) => new { e.aId, e.eId, d.cId, d.Data });

// left outer join
var o = from c in db.B
        join e in ee on new { c.aId, c.cId }
            equals new { e.aId, e.cId } into temp
        from m in temp.DefaultIfEmpty()
        select new
        {
            c.aId,
            c.cId,
            Data = null != m ? m.Data : [default value]
        };

Однако это не удается, когда я звоню o.ToString() со следующими деталями исключения:

System.ArgumentException: аргумент для DbIsNullExpression должен обратитесь к примитиву или ссылочному типу. в System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.ValidateIsNull (DbExpression аргумент, логическое allowRowType) в System.Data.Objects.ELinq.ExpressionConverter.EqualsTranslator.CreateIsNullExpression (ExpressionConverter родитель, выражение выражения) в System.Data.Objects.ELinq.ExpressionConverter.EqualsTranslator.TypedTranslate (ExpressionConverter BinaryExpression linq) в System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate (ExpressionConverter родитель, выражение linq)

... [здесь больше трассировки стека]

в System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression (Expression linq) в System.Data.Objects.ELinq.ExpressionConverter.Convert ()
в System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan (Nullable 1 forMergeOption) at System.Data.Objects.ObjectQuery.ToTraceString() at System.Data.Entity.Internal.Linq.InternalQuery 1.ToString () в System.Data.Entity.Infrastructure.DbQuery`1.ToString ()

Я пытался сформировать подобный запрос, используя методы расширения, но у меня было то же исключение. Что мне здесь не хватает?

-------------------------------------------- -------------------------------------

EDIT:

Похоже, проблема связана со строкой

Data = null != m ? m.Data : [default value]

Я изменил его на

   Data = m

И это начало работать. Я должен переместить нулевую логику проверки в то место, где я использую результат. Теперь мне интересно, что может быть причиной исключения? Из подробностей исключения видно, что он не может определить m (который является анонимным типом) как ссылочный тип. Это поведение где-то задокументировано?

1 Ответ

3 голосов
/ 10 октября 2011

Ну, вы проверяли объединенную сущность на ноль, что не имеет смысла с точки зрения sql. Следующее должно быть правильно истолковано как объединение:

Data = m.Data ?? [default value]
...