Could Someone Tell Me How This Code Throws an Error?
matttrax
Member Posts: 2,309
I'm trying to post an Item Journal to negatively adjust some inventory. Everything is tracked by a serial so there are item tracking lines for every journal line. When the posting routine gets to the second line it errors out, saying that "Value Entry xxxx already exists." The value entry that does already exist has nothing to do with the line that is being posted, and in fact shouldn't even come up in the filters.
I have looked at the debugger to see that no other filters are applied. It is only the Item Ledger Entry No. It is filtering on the correct Item Ledger Entry, but when it does a FIND 1) It errors out somehow even though it's in a conditional statement and 2) The Value Entry that already exists does not have that Item Ledger Entry on it.
The following code is from Codeunit 22. Function EnsureValueEntryLoaded(ValueEntry,ItemLedgEntry)
It is called by Codeunit 22 in the Function TouchItemEntryCost(ItemLedgerEntry,IsAdjustment)
I have looked at the debugger to see that no other filters are applied. It is only the Item Ledger Entry No. It is filtering on the correct Item Ledger Entry, but when it does a FIND 1) It errors out somehow even though it's in a conditional statement and 2) The Value Entry that already exists does not have that Item Ledger Entry on it.
The following code is from Codeunit 22. Function EnsureValueEntryLoaded(ValueEntry,ItemLedgEntry)
ValueEntry.SETCURRENTKEY("Item Ledger Entry No.");
ValueEntry.SETRANGE("Item Ledger Entry No.",ItemLedgEntry."Entry No.");
IF ValueEntry.FIND('-') THEN; <-- Error thrown here
It is called by Codeunit 22 in the Function TouchItemEntryCost(ItemLedgerEntry,IsAdjustment)
ItemLedgerEntry."Applied Entry to Adjust" := TRUE;
WITH ItemLedgerEntry DO
SetAdjmtProp("Item No.",ItemLedgerEntry."Entry Type",IsAdjustment,"Prod. Order No.",
"Prod. Order Line No.","Posting Date","Posting Date");
IF NOT IsAdjustment THEN BEGIN
EnsureValueEntryLoaded(ValueEntry,ItemLedgerEntry); // <---- Here
AvgCostAdjmtEntryPoint.UpdateValuationDate(ValueEntry);
END;
0
Answers
-
You have been hit by the buffering mechanism of NAV!
When NAV (all native without debugger) and also from some version under SQL buffers the insert into tables UNTIL some command requests a return from the DB-server. In that moment NAV sends all the inserts to SQL and you might hit the error. Search for an INSERT-statement on that table and for testing, change it toIF TheTable.INSERT THEN ;
This will immediately trigger the error.Regards,Alain Krikilion
No PM,please use the forum. || May the <SOLVED>-attribute be in your title!0 -
kriki wrote:You have been hit by the buffering mechanism of NAV!
When NAV (all native without debugger) and also from some version under SQL buffers the insert into tables UNTIL some command requests a return from the DB-server. In that moment NAV sends all the inserts to SQL and you might hit the error. Search for an INSERT-statement on that table and for testing, change it toIF TheTable.INSERT THEN ;
This will immediately trigger the error.
Interesting, I thought this was only in Native. Do you know which versions of SQL this happens in?David Singleton0 -
bulk inserting was introduced with 5.0 sp10
-
Well, the question why the error is thrown lately may be answered but why is there such a kind of error at all? At first I would ensure that the already existing value entry is definitely created during the active transaction. To test this, please take a look at the value entry table (object designer) after the error occured and search for the value entry with the entry no. corresponding to the error message. It may be (though unlikely but theoretically) possible that someone has deleted some item ledger entries (with an appropriate license, of course) and forgot the value entries (and may be the application entries, too).New kits on the blog: https://massivedynamicsblog.wordpress.com0
-
-
Probably it is not the problem. Each insert of an entry-table is done by locking the table and taking the last record (on SQL, only this last record is exclusively locked) and then adding 1 to the Entry No.gerdhuebner wrote:Well, the question why the error is thrown lately may be answered but why is there such a kind of error at all? At first I would ensure that the already existing value entry is definitely created during the active transaction. To test this, please take a look at the value entry table (object designer) after the error occured and search for the value entry with the entry no. corresponding to the error message. It may be (though unlikely but theoretically) possible that someone has deleted some item ledger entries (with an appropriate license, of course) and forgot the value entries (and may be the application entries, too).
I think someone is inserting extra value entries by non-standard NAV code.
If you post more than 1 item ledger at a time, the last used Value entry "Entry No." is saved to avoid having to lock the table and get the last value entry again. If extra records are created by non-standard NAV code, this generates problems.
This is the reason I said to use "IF TheTable.INSERT THEN ; ".
And now that I think about it: I made a mistake. previous insert would avoid the error.
It should be :IF NOT ValueEntry.INSERT THEN ERROR('Value entry %1 already exists',ValueEntry."Entry No.");Regards,Alain Krikilion
No PM,please use the forum. || May the <SOLVED>-attribute be in your title!0 -
I could reproduce the above described behavior by deleting the last few item ledger entries from table 32 manually and trying to post an item journal.
As Kriki already pointed out, the reason why the error within the debugger occurs so lately is true to the new so called bulk-inserts-feature, which was introduced in NAV 5.0 (SP1) - see for example:
http://blogs.msdn.com/microsoft_dynamics_nav_sustained_engineering/archive/2008/04/14/bulk-inserts-in-microsoft-dynamics-nav-5-0-sp1.aspx
This feature applies only to SQL server. If you try the same within the native server, the debugger will stop at the right position.
It may be worth noting, that in the case of item journal posting (and other posting routines), the amount of time that a table is locked (this is claimed to be the main purpose of the new feature) is not reduced - at least not for the item ledger entry and value entry tables - because the locking immediately (and inevitably) becomes effective right in the beginning of codeunit 22 due to the usual LOCKTABLE - FINDLAST commands.
There is another remarkable point, yet:
So why is there an error at all, if the posting routine simply adds value entries with the next free entry no.?kriki wrote:...Each insert of an entry-table is done by locking the table and taking the last record (on SQL, only this last record is exclusively locked) and then adding 1 to the Entry No.
The reason is due to the function EnsureValueEntryLoaded, which has already been posted in the beginning:ValueEntry.SETCURRENTKEY("Item Ledger Entry No."); ValueEntry.SETRANGE("Item Ledger Entry No.",ItemLedgEntry."Entry No."); IF ValueEntry.FIND('-') THEN;Now it is clear, that the ValueEntry with the next free entry no. is switched back to a lower entry no., because there already exists a value entry for the corresponding Item Ledger Entry (which has been deleted before). In some respect I find it striking that the same piece of code where the debugger more or less accidentally stops is responsible for the error in the end...
By the way, someone should check if the ValueEntry.FIND('-') should be changed to ValueEntry.FIND('+') - I'm worrying about the case when there exist two or more value entries for an item ledger entry...New kits on the blog: https://massivedynamicsblog.wordpress.com0 -
It was the buffer issue, but the real reason was because I had value entries with no corresponding item ledger entry. I was creating a test database and accidentally copied these value entries over as I didn't really feel like writing code to create thousands of journal lines and post them.
On the one hand yes it's bad (very very bad) to delete ledger entries and import directly into the ledger instead of a journal. But on the other, I don't know if there's a better way to really learn all those dependencies.
And then you learn / remember other things, like the buffer issue. 0 -
Well, it doesn't really help postponing the locking time, but it definitly helps to speed up a lot of inserts in the same table (but only if no other actions happen on that table). See also http://mibuso.com/blogs/kriki/2008/04/01/sql-changes-for-50sp1/gerdhuebner wrote:It may be worth noting, that in the case of item journal posting (and other posting routines), the amount of time that a table is locked (this is claimed to be the main purpose of the new feature) is not reduced - at least not for the item ledger entry and value entry tables - because the locking immediately (and inevitably) becomes effective right in the beginning of codeunit 22 due to the usual LOCKTABLE - FINDLAST commands.Regards,Alain Krikilion
No PM,please use the forum. || May the <SOLVED>-attribute be in your title!0
Categories
- All Categories
- 73 General
- 73 Announcements
- 66.7K Microsoft Dynamics NAV
- 18.8K NAV Three Tier
- 38.4K NAV/Navision Classic Client
- 3.6K Navision Attain
- 2.4K Navision Financials
- 116 Navision DOS
- 851 Navision e-Commerce
- 1K NAV Tips & Tricks
- 772 NAV Dutch speaking only
- 617 NAV Courses, Exams & Certification
- 2K Microsoft Dynamics-Other
- 1.5K Dynamics AX
- 327 Dynamics CRM
- 111 Dynamics GP
- 10 Dynamics SL
- 1.5K Other
- 990 SQL General
- 383 SQL Performance
- 34 SQL Tips & Tricks
- 35 Design Patterns (General & Best Practices)
- 1 Architectural Patterns
- 10 Design Patterns
- 5 Implementation Patterns
- 53 3rd Party Products, Services & Events
- 1.6K General
- 1.1K General Chat
- 1.6K Website
- 83 Testing
- 1.2K Download section
- 23 How Tos section
- 252 Feedback
- 12 NAV TechDays 2013 Sessions
- 13 NAV TechDays 2012 Sessions


