2009-09-16 4 views
1

У меня есть 3 таблицы: Principal (Principal_ID, Scale), Frequency (Frequency_ID, Value) и Visit (Visit_ID, Principal_ID, Frequency_ID). мне нужен запрос, который возвращает все принципал (в главной таблице), и для каждой записи, запрашивать необходимую емкость для этого принципала, рассчитанную, как показано ниже:Задача сложного запроса LINQ to SQL

Capacity = (Principal.Scale == 0 ? 0 : (Frequency.Value == 1 ? 1 : Frequency.Value * 1.8)/Principal.Scale) 

Я использую LINQ для SQL, так что здесь является запрос:

from Principal p in ShopManagerDataContext.Instance.Principals 
    let cap = 
    (
      from Visit v in p.Visits 
      let fqv = v.Frequency.Value 
     select (p.Scale != 0 ? ((fqv == 1.0f ? fqv : fqv * 1.8f)/p.Scale) : 0) 
    ).Sum() 
    select new 
    { 
      p, 
      Capacity = cap 
    }; 

Сформированный TSQL:

SELECT [t0].[Principal_ID], [t0].[Name], [t0].[Scale], (
    SELECT SUM(
     (CASE 
      WHEN [t0].[Scale] <> @p0 THEN (
       (CASE 
        WHEN [t2].[Value] = @p1 THEN [t2].[Value] 
        ELSE [t2].[Value] * @p2 
       END))/(CONVERT(Real,[t0].[Scale])) 
      ELSE @p3 
     END)) 
    FROM [Visit] AS [t1] 
    INNER JOIN [Frequency] AS [t2] ON [t2].[Frequency_ID] = [t1].[Frequency_ID] 
    WHERE [t1].[Principal_ID] = [t0].[Principal_ID] 
    ) AS [Capacity] 
FROM [Principal] AS [t0] 

И Я получаю ошибку:

SqlException: Multiple columns are specified in an aggregated expression containing an outer reference. If an expression being aggregated contains an outer reference, then that outer reference must be the only column referenced in the expression. 

И идеи, как решить это, если возможно, в одном запросе?

спасибо, что заблаговременно!

ответ

1

Вот 2 способа сделать это, изменив свой подход:

  1. Создать пользовательскую агрегатную функцию с помощью SQL CLR. Это не может быть правильным решением для вас, но это идеально подходит для проблемы, как указано. Во-первых, это переместило бы всю логику в слой данных, чтобы LINQ имел ограниченную ценность. При таком подходе вы получаете эффективность, но на вашу архитектуру большое влияние.
  2. Таблицы загрузки и Fequency в типизированный DataSet и используйте LINQ для наборов данных. Это, вероятно, будет работать с использованием существующего кода, но я не пробовал. При таком подходе ваша архитектура более или менее сохраняется, но вы можете получить большую эффективность, если Видение и частота велики.
+0

Загрузка его в типизированных DataSet это не вариант, я должен был бы полностью переписать большую часть программы. Я рассмотрю функции агрегации SQL CLR, спасибо. – ShdNx

1

Основываясь на комментарии, у меня есть альтернативное предложение. Поскольку ваша ошибка исходит из SQL, и вы не используете новый столбец в качестве фильтра, вы можете переместить ваш расчет клиенту. Для этого вам нужно будет вытащить все соответствующие записи (используя DataLoadOptions.LoadWith <> в вашем контексте).

Чтобы ваше желание использовать привязку к DataGrid, было бы проще всего похоронить сложность в собственности Principal.

partial class Principal 
{ 
    public decimal Capacity 
    { 
     get 
     { 
      return this.Scale == 0 ? 0 : this.Visits.Select(v => 
       (v.Frequency.Value == 1 ? 1 : v.Frequency.Value * 1.8)/this.Scale).Sum(); 
     } 
    } 
} 

Тогда ваш поиск получает действительно прост:

using (ShopManagerDataContext context = new ShopManagerDataContext()) 
{ 
    DataLoadOptions options = new DataLoadOptions(); 
    options.LoadWith<Principal>(p => p.Visits); 
    options.LoadWith<Visit>(v => v.Frequency); 
    context.LoadOptions = options; 

    return (from p in context.Principals 
      select p).ToList(); 
} 
+0

Да, я пробовал это раньше, но сообщение об исключении одно и то же. На самом деле, если вы посмотрите на сгенерированный ИЛ, это то же самое. – ShdNx

+0

Я вижу. Это больше о p.Scale, являющемся внешней ссылкой, чем о наличии нескольких столбцов. –

+1

Я изменил свой ответ на обработку на клиенте. Я не уверен, что он будет действителен для вашей ситуации, но на этот раз он должен работать реально ... :) –

Смежные вопросы