Converting ABL to C#; Errors CS0324, CS0103 & CS1061

,

When using the ABL Code Converter, https://scrs.epicor.com/ABLConversionweb/ I have received the following errors and unsure how to resolve them?

ABL Code:

for each ttgljrngrp .
for each userfile where userfile.DcdUserID = ttCallContextClient.CurrentUserID .
ttgljrngrp.character01 = userfile.Name .
end.
end.

Converted Code:

Erp.Tables.userfile userfile;
foreach (var ttgljrngrp_xRow in ttgljrngrp)
{
var ttgljrngrpRow = ttgljrngrp_xRow;
foreach (var userfile_iterator in (from userfile_Row in Db.userfile
where userfile_Row.DcdUserID == this.callContextClient.CurrentUserID
select userfile_Row))
{
userfile = userfile_iterator;
ttgljrngrp_xRow[“character01”] = userfile.Name;
}
}

CS0324 - The type or namespace name ‘userfile’ does not exist in the namespace ‘Erp.Tables’ (are you missing an assembly reference?)

CS0103 - The name ‘ttgljrngrp’ does not exist in the current context

CS1061 - ‘ErpContext’ does not contain a definition for ‘userfile’ and no extension method ‘userfile’ accepting a first argument of tye ‘ErpContext’ could be found (are you missing a using directive or an assembly reference?)

CS1061 - ‘BpmClientInfo’ does not contain a definition for ‘CurrentUserID’ and no extension method ‘CurrentUserID’ accepting a first argument of type ‘BpmClientInfo’ coudl be found 9are you missing a using directive or an assembly reference?)

I think the table references need to be the proper case like: ttGLJrnDtl

Replace ever instance of userfile with UserFile and
ttgljrngrp with ttGLJrnGrp

The following passes a syntax check in a pre-process MD.

Erp.Tables.UserFile UserFile;

foreach (var ttGLJrnGrp_xRow in ttGLJrnGrp)
  {
  var ttGLJrnGrpRow = ttGLJrnGrp_xRow;
  foreach (var UserFile_iterator in (from UserFile_Row in Db.UserFile
  where UserFile_Row.DcdUserID == this.callContextClient.CurrentUserId
  select UserFile_Row))
    {
    UserFile = UserFile_iterator;
    ttGLJrnGrp_xRow["character01"] = UserFile.Name;
    }
  }

The code converter is not always efficient, nor does it always know your intent…
Your code can be simplified even more to something like this… note that if the userID is not found, then this also returns a “Not Found” using the coalesce (??) option. The query to get the name also only returns the one field that you want making it much more efficient (you never want to return the entire record if you only want a couple of fields).

foreach (var glJrnGrp in ttGLJrnGrp.Where(x => x.RowMod != "")) {
    glJrnGrp["Character01"] = Db.UserFile.Where(x => x.DcdUserID == callContextClient.CurrentUserId).Select(x => x.Name).FirstOrDefault() ?? "Not Found";
}
1 Like

Should a foreach(...){} be used even if you know that the tt... table will only contain one record?

Is there much overhead in a for-loop that only executes once?

in theory the foreach is not needed… but it is sometimes easier than doing a null check.
The lines could be as follows without the foreach… but it essentially does the same thing, and takes one more line of code. The “ForEach” gets the one record and processes it.

var glJrnGrp in ttGLJrnGrp.Where(x => x.RowMod != "")).FirstOrDefault();
if (glJrnGrp != null) {
    glJrnGrp["Character01"] = Db.UserFile.Where(x => x.DcdUserID == callContextClient.CurrentUserId).Select(x => x.Name).FirstOrDefault() ?? "Not Found";
}

Thanks. This LINQ stuff is new to me. I still prefer to code in C (not C++, or C#, but rather K&R’s C).

And my programming background is in embedded systems running on 8-bit mico’s. While modern compilers do a good job at optimizing, I still see for-loops as 4 distinct actions

  1. The initializtion (i=0; ...)
  2. The check for completion (...; i<max_loop; ...)
  3. The actions to perform { ...}
  4. The action to perform after #3 (... i++)

So if it is only going to happen once, steps 1, 2, and 4 are wastes of time.

(just my $0.02)

But C# is very efficient with foreach commands.

The following line - it basically sets up the loop, and automatically extracts each row of Y into x. It doesnt actually move y into x, but x references the row of Y. If there are no rows in Y, then it will skip the test altogether.
Foreach (x in Y) {
//do stuff here with x
}

1 Like

Note that I too have had a hard time transitioning from my former programming style… back in the olden days of programming an entire ERP System in “AlphaBasic” when you did a “For Next” loop, they were inefficient. You had to read records inside the loop, doing one thing at a time, updating / writing records by yourself.
I have had to simply throw away my old concepts of how things worked.
Also, a great resource for understanding how C# works and which way is most efficient is on DotNetPerls.Com , where they explain each command, give multiple variations of the command, and even show efficiencies of different methods of programming… for example C# foreach Loop Examples - Dot Net Perls shows this for the foreach command.