Error "must be reducible node" when executing left join with LinqDataAdapter (NetStandard 2.0)

Hi,

I’m getting the error “must be reducible node” when executing the following query:

var emailMessages = lda.GetTable<EmailMessages>();
var emailNotifications = lda.GetTable<EmailNotifications>();
var query = from e in emailMessages
				   where (e.MessageId == messageId)
				   join n in emailNotifications
						on new { Id = e.Email_Message_ID }
						equals new { Id = n.Email_Message_ID } into n1
				   from n2 in n1.DefaultIfEmpty()
				   select new { Email = e, Notifications = n2 };
var result = query.ToList();

This is the call stack:

System.ArgumentException: must be reducible node
   at System.Linq.Expressions.Expression.ReduceAndCheck()
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteNewExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
   at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteLambdaExpression(Expression expr)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteNewExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.Add(Expression expression)
   at System.Linq.Expressions.Compiler.StackSpiller.ChildRewriter.AddArguments(IArgumentProvider expressions)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteInvocationExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteUnaryExpression(Expression expr, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
   at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
   at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
   at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
   at RemObjects.DataAbstract.Linq.LinqDataAdapter.FillMethod(Int32[] offsets, IDataReader reader, RequestData request, Expression expression) in c:\CI\b\rofx\932\Data Abstract for .NET\Source\RemObjects.DataAbstract\Linq\LinqDataAdapter.pas:line 875
   at RemObjects.DataAbstract.Linq.RemoteTable`1.<>c__DisplayClass0.<Execute>b__0(Int32 index, Int32[] offsets, IDataReader reader) in c:\CI\b\rofx\932\Data Abstract for .NET\Source\RemObjects.DataAbstract\Linq\RemoteTable.pas:line 293
   at RemObjects.DataAbstract.Linq.LinqRemoteDataAdapter.FetchData(TableRequestInfo[] tableRequest, String[] tableNames, Action`3 fillMethod) in c:\CI\b\rofx\932\Data Abstract for .NET\Source\RemObjects.DataAbstract\Linq\LinqRemoteDataAdapter.pas:line 431
   at RemObjects.DataAbstract.Linq.RemoteTable`1.Execute(Expression expression, DataParameter[] parameters) in c:\CI\b\rofx\932\Data Abstract for .NET\Source\RemObjects.DataAbstract\Linq\RemoteTable.pas:line 296
   at RemObjects.DataAbstract.Linq.RemoteTableQuery`1.GetEnumerator() in c:\CI\b\rofx\932\Data Abstract for .NET\Source\RemObjects.DataAbstract\Linq\RemoteTableQuery.pas:line 74
   at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   (...)

The project is a .NET Core 2.1 project, using the NetStandard assemblies. Is there something wrong with the LINQ statement? If I change it to an inner join, it works fine.

Thanks,
Arturo.

I tried the following variations, which result in the same exact query generated (the query line), but also the same error when executed (the .ToList() line):

var query = from e in emailMessages
				   where (e.MessageId == messageId)
				   join n in emailNotifications on e.Email_Message_ID equals n.Email_Message_ID into n1
				   from n2 in n1.DefaultIfEmpty()
				   select new { Email = e, Notifications = n2 };
var result = query.ToList();

and

var companyQuery = from e in emailMessages
				   where (e.MessageId == messageId)
				   from n in emailNotifications
						.Where(notification => notification.Email_Message_ID == e.Email_Message_ID)
						.DefaultIfEmpty()
				   select new { Email = e, Notifications = n };
var result = query.ToList();

So it seems to be something in DA’s LINQ processor.

Thanks,
Arturo.

Thanks, logged as bugs://82541

Well, this construction is not supported by DA LINQ (even in full .NET). Columns of the linked table have to be explicitly listed in the resulting Select to allow the query processor to do its job.

In other words this query will fail:

		var query = from o in orders
			join od in orderDetails on o.Id equals od.OrderId into oj
			from od in oj.DefaultIfEmpty()
			select new { Order = o, Details = od };

While this one does work:

		var query = from o in orders
			join od in orderDetails on o.Id equals od.OrderId into oj
			from od in oj.DefaultIfEmpty()
			select new {Order = o, Details = new OrderDetails {Id = od.Id, OrderId = od.OrderId}};

I’ve logged an issue, however due to the insane complexity of the DA LINQ internals I cannot promise any ETA to simplifying this (ie to allow the 1st query to work as well). Tbh at this moment I am not even sure if that is possible at all.

Thanks, no problem. I can use the suggested workaround when I need to do a left outer join.

Arturo.