Подтвердить что ты не робот

Вложенный запрос в инфраструктуре сущности

Я получаю следующее исключение:

Вложенный запрос не поддерживается. Operation1 = 'Case' Operation2 = 'Collect'

с этим запросом

var Games = context.Games.Select(a => new GameModel
{
     Members = (a.Type == 1 ? (a.UsersInGames.Where(b => b.GameID == a.ID && b.StatusID == 1).Select(c => new Member
     {
         ID = c.UserID,
         email = c.UserInfo.EmailAddress,
         screenName = c.UserInfo.ScreenName
     })) :   
    (a.Teams.Where(b => b.GameID == a.ID).SelectMany(b => b.UsersInTeams.Where(c => c.StatusID == 1)).Select(d => new Member
    {
        ID = d.UserID,
        email = d.UserInfo.EmailAddress,
        screenName = d.UserInfo.ScreenName
    )))
})

когда я не включаю условие при выборе членов, запрос работает нормально. Есть ли способ сделать условие внутри запроса?

4b9b3361

Ответ 1

Вы переоцениваете силу перевода LINQ на SQL. Не все переводимые, и для этого не существует предупреждений компилятора из-за того, как работает LINQ.

Вложенные коллекции обычно либо a) не поддерживаются, либо b) попадают в ужасные запросы SELECT N + 1. То, что вы попросите EF, - это вернуть дерево объектов. SQL не поддерживает древовидные результаты, поэтому вы сталкиваетесь с несоответствием объектно-реляционного импеданса, и это больно.

Я советую вам вставить данные вложенных данных в виде второго, полностью отдельного запроса. Это позволяет вам больше контролировать и гарантированно работать.

Как несущественная сторона - node, вы, вероятно, не сможете убедить EF использовать оператор?: над последовательностями. Это очень сложно перевести. Подумайте, как вы могли бы написать это как SQL - очень сложно и запутанно.

Ответ 2

Похоже, что Linq to EF не поддерживает следующие

context.Games.Select(g => new
{
    Field = g.IsX? queryable1 : queryable2
});

Но вот здесь вы можете использовать хак, чтобы заставить его работать:

context.Games.Select(g => new
{
    Field = queryable1.Where(q => g.IsX)
               .Concat(queryable2.Where(q => !g.IsX))
});

Ответ 3

Я столкнулся с той же проблемой. Решение было загрузить оба результата и определить, что использовать после запроса (я знаю, что это имеет недостаток производительности), но по крайней мере вы можете сделать это временно, если крайний срок нападает на вас

На стороне LINQ

  var Games = context.Games.Select(a => new GameModel
        {
            // carries type1 results
            Members = a.UsersInGames.Where(b => b.GameID == a.ID && b.StatusID == 1).Select(c => new Member
            {
                ID = c.UserID,
                email = c.UserInfo.EmailAddress,
                screenName = c.UserInfo.ScreenName
            })),

             //You need to create this temporary carrier to carry type 2 results
             MembersOfType2 = a.Teams.Where(b => b.GameID == a.ID).SelectMany(b => b.UsersInTeams.Where(c => c.StatusID == 1)).Select(d => new Member
                {
                    ID = d.UserID,
                    email = d.UserInfo.EmailAddress,
                    screenName = d.UserInfo.ScreenName
                })))
            })
        }

После этого вы можете выполнить цикл Games и сделать назначение Members = MembersOfType2, если Type == 1 для определенной игры.