- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Grouping Exception Object reference not set to an instance of an object
Greeting,
when executing this query by LINQ it through Exception Object reference not set to an instance of an object
select T1.EmpID,T2.EmpID,suM(T1.salary),sum(T2.Loan)
from T1 inner join T2
on t1.empID=t2.empID
group by T1.EmpID,T2.EmpID
this is LINQ
var xx = from t in metaData.T1
join t0 in metaData.T2 on t.EmpID equals t0.EmpID
group new { t, t0 } by new { t.EmpID, C1 = t0.EmpID } into g
select new
{
EmpID = g.Key.EmpID,
Column2 = g.Sum(p => p.t.Salary),
Column3 = g.Sum(p => p.t0.Loan)
};
var data = xx.ToList(); // Exception
Exception Detail
System.NullReferenceException was unhandled
Message="Object reference not set to an instance of an object."
Source="SD.LLBLGen.Pro.LinqSupportClasses.NET35"
StackTrace:
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleAggregateExpressionReferencingGroupBy(AggregateExpression expressionToHandle, Expression handledSource, QueryExpression handledSourceAsQuery, Expression handledArgument)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleAggregateExpression(AggregateExpression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleNewExpression(NewExpression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleProjectionExpression(ProjectionExpression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleSelectExpression(SelectExpression expressionToHandle, SelectExpression newInstance)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleSelectExpression(SelectExpression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleSelectExpression(SelectExpression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle)
at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression)
at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.Execute(Expression expression)
at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression)
at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.Execute()
at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at test.BL.Individual.GetData() in C:\Test\Test.BL\Individual.cs:line 49
at Test.Win.Form1.button2_Click(Object sender, EventArgs e) in C:\Test\Test.Win\Form1.cs:line 63
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Test.Win.Program.Main() in C:\Test\Test.Win\Program.cs:line 17
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
runtime version data 21-1-2009 LLBL version 2.6 Adapter Using c# 3.5
Now i change it to
//select a.EmpID,a.salary,b.loan
//from(
//select T1.EmpID as EmpID,suM(T1.salary) as salary
//from T1
//group by T1.EmpID) a
//inner join (select T2.EmpID as EmpID,suM(T2.loan) as loan
//from T2
//group by T2.EmpID) b
//on a.EmpID=b.EmpID
var aa = from a in
(
(from t in metaData.T1
group t by new{t.EmpID} into g
select new
{
EmpID = (System.Int32?) g.Key.EmpID,
salary = g.Sum(p => p.Salary)
}))
join b in
(
(from t in metaData.T2
group t by new{t.EmpID} into g
select new
{
EmpID = (System.Int32?) g.Key.EmpID,
loan = g.Sum(p => p.Loan)
})) on a.EmpID equals b.EmpID
select new
{
EmpID = (System.Int32?) a.EmpID,
a.salary,
b.loan
};
and its worked
but why doesn't previous query work ??
Not sure, I'll try to reproduce it.
(edit) I think I know what's the cause: the grouping in your initial query is between entities into an anonymous type. I fear this particular case has no code path. I'll see if I can add that. (as I see it's not a situation we thought of when writing the linq provider). The main reason for that is I think that the new {t, t0} set to group on is actually the join again but it's not inside the expression tree as a reference to the join. So the set to group on (new {t, t0} ) is something which is in-scope but not referred to as the join.
The main problem now is that in the expression tree the fields to aggregate are referring to the join'ed set (as linq is a pipeline, so every operator operates on the result of the previous operator), so the original table these fields are in is unknown. I used a trick to get this info by looking at the groupby's selection lambda, which contains the source to group and used the alias of that source (as it's the same source the aggregate works on). However, with your query, that's not going to work.
I tried linq to sql, it does figure out the right table to pull the aggregate field from but I have no idea how to do that. (there's no documentation whatsoever about this from MS). The main problem is that the source of the aggregate function in the linq query is the group by result and the source of the groupby is the joined set. Nowhere is it possible to obtain the REAL source of the aggregated field, at least I haven't found one other than the trick I described above (which fails in your case).
I'll see if I can still pull this info, but it's not the first time this problem has been challenged (last time we found the trick with the grouped source), so I have little hope I find something, although it should be possible as linq to sql can do it (but I don;t know how it obtains the necessary info).
When I switch off the scoping of aliases inside the linq provider, it gives a proper query. Scoping is used to produce aliases which are inside a scope and not reachable outside the scope. For example: select * from (select a., b. from a join b on ...) c
here 'a' and 'b' are local aliases and not reachable for code outside the subquery, they should use 'c'. Here it's similar: an element refers to an element inside a scope (the join) and gets the alias of the join set, not the alias of the original element inside the join. The problem now is: when is the join a scope on its own for the elements referring to it, and when is it not a scope... I'll look into it.
Fixed in next build. It was a very nasty error: alias scoping is something which is necessary but there's no knowledge outside MS when and how to do this properly in all situations, so trial/error code is required. A problem is that at one point the logic has to make a decision in a narrow scope (e.g. handling of an aggregate function expression) which has influence on the handling of another part of the tree which seems unrelated (e.g. group by handling). Caused by the fact that group by statements on SQL are different than in Linq (and also why Linq's design is utterly flawed).
Anyway, I managed to add code which deals with this
I'll correct the other issue you reported as well, so you'll see a new build attached to that thread.