Apparently, LINQ method syntax for joins is broken in BPMs...?

@HLalumiere which version have you noticed this slowness on?

I do see in 2023.2 Epicor added this to Epicor.System.dll and they are trying to migrate from EF 6 to EF Core, it may be possible that a EF Core Bug exists.



This means nothing, but just to showcase that they are tinkering with EF Helpers and temp workarounds

But lets run Joses Query on your version and see what speeds you get.

1 Like

@HLalumiere you got some heavy hitters gracing thread

I added these equal queries of each syntax to a BPM

var queryMethodSyntax = Db.Part
    .Join(Db.PartRev, part => new { part.Company, part.PartNum }, rev => new { rev.Company, rev.PartNum }, (part, rev) => new { part, rev })
    .Where(joined => joined.rev.Approved == true)
    .Select(joined => new { joined.part, joined.rev });
var queryRegularSyntax =
    from part in Db.Part
    join rev in Db.PartRev on new { part.Company, part.PartNum } equals new { rev.Company, rev.PartNum }
    where rev.Approved == true
    select new { part, rev };

I then decompiled them and the decompiled code out of Ice.CustomizationStore was the same with the exception of one directly queryable the other was an anonymous function delegate. So even at the c# level nothing is managed different in terms of memory. This would indicate no funny business from Epicor.

When I looked into the diffrence between the expression tree vs enumerable it actually sounds like the enumerable would possibly be microseconds slower and one occurs in memory and the other out of memory. That just determines when the query happens though nothing else. one occurs when the statement is written the other occurs when you start a foreach on it. Timing nothing else that I can find.

3 Likes

Do you really need it?

Func<IQueryable, string> GetSQLString = (queryObject) =>
{
    System.Data.Entity.Core.Objects.ObjectQuery objectQuery = (System.Data.Entity.Core.Objects.ObjectQuery) queryObject;
    
    return objectQuery.ToTraceString();
}; 



var query = Db.ABCCode.Where(x => x.Company == "YourCompany");
//var query = from abc in Db.ABCCode where abc.Company == "YourCompany" select abc;


output = GetSQLString(query);
SELECT 
    [Extent1].[Company] AS [Company], 
    [Extent1].[ABCCode] AS [ABCCode], 
    [Extent1].[CountFreq] AS [CountFreq], 
    [Extent1].[ExcludeFromCC] AS [ExcludeFromCC], 
    [Extent1].[StockValPcnt] AS [StockValPcnt], 
    [Extent1].[PcntTolerance] AS [PcntTolerance], 
    [Extent1].[CalcPcnt] AS [CalcPcnt], 
    [Extent1].[CalcQty] AS [CalcQty], 
    [Extent1].[CalcValue] AS [CalcValue], 
    [Extent1].[QtyTolerance] AS [QtyTolerance], 
    [Extent1].[ValueTolerance] AS [ValueTolerance], 
    [Extent1].[ShipToCustNum] AS [ShipToCustNum], 
    [Extent1].[SysRevID] AS [SysRevID], 
    [Extent1].[SysRowID] AS [SysRowID]
    FROM [Erp].[ABCCode] AS [Extent1]
    WHERE N'YourCompany' = [Extent1].[Company]
2 Likes

I can’t easily move that where clause cause the orderHed table isn’t available down there without selecting it down into the 3rd join it isn’t a trivial swap. I can add a where clause for something else.

2 Likes

It’s OK, I am redoing it with slight mods and getting the SQL from server logs.

Thanks!

1 Like

Just send your reliable source to this thread and call it a day lol

Lol :headstone:

@HLalumiere your reliable source is probably going to know or have met the names on this thread at one point.

And @HLalumiere we would all love nothing more than to be taught something new, that’s why this forum exists. If they want to add to the existing, rich discourse that would only strengthen this forum.

Tested on my own end. exactly the same SQL in both cases… Case definitely closed.

2 Likes

Any case is getting closed if you have @josecgomez, @jgiese.wci, @hkeric.wci , and @klincecum on it.

2 Likes

Nothing wrong with this thread, its good to share assumptions so we can together debunk or confirm them, and let Epicor know about a bug so when we upgrade to the latest version we have it fixed already.

Why should we all suffer when we can just have someone like @josecgomez suffer first then tell us about the “gotchas” :slight_smile:

I am no longer upgrading first, done that for years. It’s Kevin’s turn.

1 Like

Yup, hence why I posted in the first place… Made no sense to me, but you know what they say about assuming things… :slight_smile:

1 Like

There is absolutely nothing wrong with this thread, I hope I never caused any confusion about that. This thread is what it’s all about. Love it!

There’s a pretty good chance that I’m the mysterious “reliable source” so allow me to dispel some confusion.

I reviewed a BPM that was reading an entire table (as confirmed via SQL Profiler) as part of an EF query. I rewrote the query to fix the issue and could now see the where clause in the profiler.

The fact that it was re-written in query syntax instead of method syntax has nothing to do with the fix. Either syntax will compile to the same thing and Epicor is not doing anything nefarious here.

It is possible to write a good query with either syntax and a bad query with either syntax. The bottom line is that the problem was a bad query, not the flavour of syntax.

Method syntax was not discouraged nor blamed as the source of the problem. If I gave that impression (assuming I’m the mystery man) then I’ll take the blame for not being clearer.

#nosyntaxconspiracy

4 Likes

You get extra points for re-writing in query syntax cause Fluent Syntax SUX!!! #LinqQueryForLife #LambdaIsHardToRead #Dont@Me :yum:

4 Likes

Hahaha love it @Epic_Santiago , yeah that was the first thing that was stated, maybe there was a misunderstanding on @HLalumiere 's part or maybe the mysterious source wasn’t clear enough.

Whoever gave you that information either misunderstands how things work or maybe something was lost in translation. - @josecgomez

I feel the same way, but I know other’s might get heated when seeing all that nonsense haha. I am glad I am not the only one.

funny face laugh GIF by Alpha

1 Like