LINQ to SQL выдает исключение SQL с использованием локальной коллекции

Amounts = 
    Context.Ppm_TblCodeType
    .Where(bc => bc.OrganisationId == Contract.OrganisationId)
    .Select(bc => new MacroPaymentValue
    {
        Code = bc.CodeTypeCode,
        ShortName = bc.ShortDescription,
        ValueForPayment = visits
            .Where(v => v.Detail.CodeTypeCode == bc.CodeTypeCode)
            .Sum(v => v.Detail.Charge != null ? v.Detail.Charge.Value : 0)
     }).ToArray();

Я получаю исключение: локальную последовательность нельзя использовать в реализациях операторов запросов LINQ to SQL, кроме оператора Contains.

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


person tigerswithguitars    schedule 09.11.2012    source источник


Ответы (2)


Это происходит потому, что вы пытаетесь использовать visits, который является локальной последовательностью в вашем коде, как часть запроса, и LINQ to SQL не может преобразовать это в SQL.

Глядя на ваш код, я думаю, вам лучше заполнить ValueForPayment, как только вы получите результат запроса в памяти. Что-то типа:

Amounts = 
    Context.Ppm_TblCodeType
    .Where(bc => bc.OrganisationId == Contract.OrganisationId)
    .Select(bc => new MacroPaymentValue
    {
        Code = bc.CodeTypeCode,
        ShortName = bc.ShortDescription,
        CodeTypeCode = bc.CodeTypeCode,
        ValueForPayment = 0
     }).ToArray();

foreach(var bc in Amounts) 
{
    bc.ValueForPayment = visits
            .Where(v => v.Detail.CodeTypeCode == bc.CodeTypeCode)
            .Sum(v => v.Detail.Charge != null ? v.Detail.Charge.Value : 0)
}
person James Gaunt    schedule 09.11.2012
comment
Это именно то, что я сделал, чтобы исправить проблему. Выглядит намного более классическим, чем LINQy ... но это небольшая жертва для рабочего и читаемого кода. - person tigerswithguitars; 09.11.2012

Это вызывает исключение, потому что вы пытаетесь использовать visits, а не потому, что вы вызываете sum (). Может помочь, если вы включили часть кода, в которой создаете список посещений ...

Откуда это взялось, и можно ли его запросить в этом же утверждении?

Так что что-то вроде этого будет работать:

Context...Select(bc => new MacroPaymentValue() 
{
    //stuff
    ValueForPayment =     bc.visits.sum(...)
});

Фактически, я заметил, что в конце этого запроса вы заставляете его использовать ToArray (). Если вы делаете то же самое с запросом посещений, он превращает запрос в локальную последовательность. Просто избавившись от части ToArray () в запросе посещений, вы получите IQueryable, который можно использовать в других запросах linq.

Поэтому, если посещения действительно должны происходить за пределами TblCodeType, вы можете просто убедиться, что не используете ToArray ().

По сути, вы не можете использовать локальный массив в запросе linq to sql (по большей части). Однако вы можете использовать другой запрос в запросе linq to sql. Если вы вызываете ToArray () или ToList (), он фактически выполнит запрос, получит результаты и сохранит их в локальной последовательности (массив или список, в зависимости от того, что вы вызываете.) Если вы НЕ сделаете этого, однако запрос не запускается, пока вы не начнете использовать значения. Таким образом, запрос останется запросом и его можно будет безопасно использовать в других запросах.

person CodeRedick    schedule 09.11.2012
comment
Хороший момент ... Я смоделировал тестовое приложение и оставил посещения как IQueryable, это был монстр запроса, когда я выполнил .ToArray (), но сработал. К сожалению, в моем реальном приложении у меня нет доступа для этого, поэтому другой ответ помечен как принятый. ТАК много LINQ to Learn ... это не каламбур. - person tigerswithguitars; 09.11.2012
comment
Возможно, вы захотите поработать с тем, кто отвечает за запрос о посещениях, тогда ... есть еще и эффективность, о которой нужно беспокоиться. Один запрос-монстр лучше, чем два отдельных запроса. Плюс я хочу получить очки за ответы! ;) - person CodeRedick; 09.11.2012
comment
Ха! Могу я процитировать вас? Думаю, это не менее хорошая причина для меня поболтать с этой командой разработчиков. Это единственная причина, по которой я начал размещать здесь вопросы, я - конкурентоспособный парень. - person tigerswithguitars; 09.11.2012
comment
Очень рад получить очки! Просто хотел сказать, что с LINQ вполне возможно генерировать запросы, которые на самом деле не стоят сокращения обращений к БД. Я регулярно видел запросы LINQ длиной в несколько сотен строк - в основном с использованием моделей наследования EF - и получил огромную экономию времени, просто разделив его на несколько вызовов. Тем не менее, вам нужно протестировать все это, чтобы знать, как лучше всего реализовать конкретную операцию. В этом случае, хотя я подозреваю, что предложение @Telos будет быстрее, основываясь только на структуре выражения. - person James Gaunt; 11.11.2012