Hi,
I'm using v5.6.3RTM
LLBLGen runtime framework
Adapter
I have this small table UitgaveMagazijnMutatie with the following fields
UitgaveId int32
MagazijnId int32
Datum DateTime
Aantal int32
Vvp Decimal
I need an aggregate of this to sum up a count (stock on date) and amount before/on some date, so pseudo:
UitgaveId int32
MagazijnId int32
Voorraad int32 : sum of Aantal
Waarde Decimal : sum of (Aantal * Vvp)
where Datum<= [some date]
This is the code I use to fetch the results
public async Task<List<UitgaveVoorraadOpPeildatum>> GetUitgaveMagazijnVoorradenOpPeildatumAsync(DateTime peilDatum)
{
using var adapter = _dataAdapterFactory.CreateDataAccessAdapter();
var metaData = new LinqMetaData(adapter);
var q = metaData.UitgaveMagazijnMutatie.Where(x => x.Datum <= peilDatum)
.GroupBy(x => new {x.UitgaveId, x.MagazijnId})
.Select(x => new UitgaveVoorraadOpPeildatum
{
UitgaveId = x.Key.UitgaveId,
Voorraad = x.Sum(umm => umm.Aantal),
Waarde = x.Sum(umm => umm.Aantal * umm.Vvp),
MagazijnId = x.Key.MagazijnId,
PeilDatum = peilDatum
});
return await q.ToListAsync();
}
This is the SQL it generates:
SELECT [LPA_L1].[UitgaveId],
[LPA_L1].[LPAV_] AS [Voorraad],
[LPA_L1].[LPAV_1] AS [Waarde],
[LPA_L1].[MagazijnId]
FROM (SELECT [LPA_L3].[UitgaveId],
[LPA_L3].[MagazijnId],
SUM([LPA_L3].[LPAV_]) AS [LPAV_],
SUM([LPA_L3].[LPAV_]) AS [LPAV_1]
FROM (SELECT [LPLA_1].[UitgaveID] AS [UitgaveId],
[LPLA_1].[MagazijnID] AS [MagazijnId],
(CDec([LPLA_1].[Aantal]) * [LPLA_1].[VVP]) AS [LPAV_]
FROM [UitgaveMagazijnMutatie] [LPLA_1]) [LPA_L3]
WHERE ((([LPA_L3].[Datum] <= @p1)))
GROUP BY [LPA_L3].[UitgaveId],
[LPA_L3].[MagazijnId]) [LPA_L1]
There are two errors in this:
1. Function CDec in (CDec([LPLA_1].[Aantal]) * [LPLA_1].[VVP]) AS [LPAV_]
2. Where on Datum against the wrong alias: WHERE ((([LPA_L3].[Datum] <= @p1)))
- this function does not work under Access Queries, it needs a second parameter, and then still it has a confirmed bug
source:
https://stackoverflow.com/questions/31327402/cdec-in-access-sql-is-not-behaving-the-same-as-when-used-from-access-vba
Solution: it might be that the whole casting is not necessary, so you might leave out the CDec altogether. It might also be to have a convert to CDbl but it slows down the query.
I have not noticed anyone having this issue on your support forum so I guess noone else is using this case.
- The Where clause is going against alias LPA_L3 while this sub query does not fetch the Datum field, so it's out of scope of LPA_L3. But could be run on LPLA_1.
Workarounds
I have created temporary work arounds for both issues 1 and 2.
1. Use Double instead of Decimal. I add a field DoubleWaarde (to be clear) and convert Vvp to double (Aantal is not needed but is convert in the SQL as well).
2. If I create an intermediate anonymous projection to force the where and the expression early, then It works as you can see below:
public async Task<List<UitgaveVoorraadOpPeildatum>> GetUitgaveMagazijnVoorradenOpPeildatumAsync(DateTime peilDatum)
{
using var adapter = _dataAdapterFactory.CreateDataAccessAdapter();
var metaData = new LinqMetaData(adapter);
var q = metaData.UitgaveMagazijnMutatie.Where(x => x.Datum <= peilDatum)
.Select(x=> new
{
x.UitgaveId,
x.MagazijnId,
Voorraad = x.Aantal,
DoubleWaarde = x.Aantal * Convert.ToDouble(x.Vvp),
})
.GroupBy(x => new {x.UitgaveId, x.MagazijnId})
.Select(x => new UitgaveVoorraadOpPeildatum
{
UitgaveId = x.Key.UitgaveId,
Voorraad = x.Sum(umm => umm.Voorraad),
DoubleWaarde = x.Sum(umm => umm.DoubleWaarde),
MagazijnId = x.Key.MagazijnId,
PeilDatum = peilDatum
});
return await q.ToListAsync();
}
the resulting SQL works and is
SELECT [LPA_L1].[UitgaveId],
[LPA_L1].[LPAV_] AS [Voorraad],
[LPA_L1].[LPAV_1] AS [DoubleWaarde],
[LPA_L1].[MagazijnId]
FROM (SELECT [LPA_L3].[UitgaveId],
[LPA_L3].[MagazijnId],
SUM([LPA_L3].[Voorraad]) AS [LPAV_],
SUM([LPA_L3].[DoubleWaarde]) AS [LPAV_1]
FROM (SELECT [LPLA_1].[UitgaveID] AS [UitgaveId],
[LPLA_1].[MagazijnID] AS [MagazijnId],
[LPLA_1].[Aantal] AS [Voorraad],
(CDbl([LPLA_1].[Aantal]) * CDbl([LPLA_1].[VVP])) AS [DoubleWaarde]
FROM [UitgaveMagazijnMutatie] [LPLA_1]
WHERE ((([LPLA_1].[Datum] <= '2018-01-01T00:00:00')))) [LPA_L3]
GROUP BY [LPA_L3].[UitgaveId],
[LPA_L3].[MagazijnId]) [LPA_L1]
You could try this yourself with some table in Northwind if necessary.
I'd gladly like to hear your thoughts.
Thanks