J'ai 3 tables: Principal (Principal_ID, Scale), Fréquence (Frequency_ID, Value) et Visit (Visit_ID, Principal_ID, Frequency_ID). J'ai besoin d'une requête qui renvoie tous les principaux (dans la table principale), et pour chaque logging, interroger la capacité requirejse pour ce principal, calculée comme suit:
Capacity = (Principal.Scale == 0 ? 0 : (Frequency.Value == 1 ? 1 : Frequency.Value * 1.8) / Principal.Scale)
J'utilise LINQ to SQL, alors voici la requête:
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 };
Le TSQL généré:
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]
Et l'erreur que je reçois:
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.
Et des idées pour résoudre cela, si possible, dans une requête?
Merci beaucoup d'avance!
Voici 2 façons de le faire en changeant votre approche:
Basé sur le commentaire, j'ai une suggestion alternative. Comme votre erreur provient de SQL et que vous n'utilisez pas la nouvelle colonne comme filter, vous pouvez déplacer votre calcul vers le client. Pour que cela fonctionne, vous devez extraire tous les loggings pertinents (en utilisant DataLoadOptions.LoadWith <> dans votre context).
Pour faciliter votre utilisation avec la binding à un DataGrid, il serait probablement plus facile d'enterrer la complexité dans une propriété de 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(); } } }
Ensuite, votre récupération devient vraiment simple:
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(); }