Dynamics AX Unusual Table Behavior - dynamics-ax-2009

It's apparently the week for unusual AX problems. I have custom, company-independent tables in AX that on first view always shows one particular record. This occurs if you access them from a form, view the tables directly, etc.
Open a form using one of the malfunctioning tables as a datasource and you only see one record.
Open a table directly (CTRL-O), and you only see that one record. However, if you hit the green arrow to re-execute the SQL query, the rest of the records appear.
I've tried dropping and reimporting the tables, adjusting the indices, deleting a variety of record combinations, but nothing has any effect. If I delete the one row that appears, another one replaces it as the one appearing record. Add that row back in (new RecId, same data) and that row resumes its original position.
I exported these tables from another system where they were working perfectly. I also imported the exact same structure to another instance on the same Dynamics server, and everything works perfectly.
Any suggestions?

Are you absolutely sure you're running the client on the same version as your application? Check to see if your Kernel version matches the Application.

Related

How to prevent two users to edit one row from DB

i am using Spring/Hibernate/ZK. In one tab i get object from DB for editing by user, but second user can open the same tab and the same object for editing . I want to informed second user whit message like "This object is аlready open" and hide buttons for save.Тhus second user can see current data from DB to this object but can`t edint him.Is there a way to check session for this object or another way to do that.
The other answers mostly look at the database, but if all users use the same zk application to access the database, you could keep track of opened objects in the Composer or ViewModel (depending whether you use MVC or MVVM; I'll just call it controller).
Your controller would need a static list of objects that are currently modified. If a user requests to open an object that is not in the list, everything is fine and your controller enables the fields and save button. Otherwise, those are disabled and/or you display a message.
The tricky part is clearing objects from that list. If a user presses the save button, you just remove the object from the list. But what if the user doesn't and just closes the tab or their session just times out? In this case you need a callback, or a mechanism that regularly checks whether the screen is still open.
You could achieve this by adding a zk timer to the tab that pings every now and then and updates the timestamp in your static list (so make it a map). If a new user tries to edit the object, check how old the last timestamp is. If it is old enough (i.e. the previous user saved it or abandoned the screen), allow them to edit it.
Still, you have to think about what to do if a user just keeps the screen open. How long are they allowed to keep the lock on the object? This is an issue in Microsoft Office as well. If multiple users try to open an Excel file from a network location, the first one gets to lock and the others cannot save until that user saves.
You may have additional field which indicates that column is being edited. When first user starts work, the field would be updated. The second user would query object with 'on hold' status and your code would handle this.
Other way - use Hibernate #Version field in your entity. It holds object version which is incremented after every update operation. If second user would save object after first one already saved, it would throw OptimisticLockException which you could handle in your code. More about optimistic and pesimistic locking: Chapter 5. Locking. Related discussions: Hibernate Automatic Versioning and When to use #Version and #Audited in Hibernate?
The best solution is to use Optimistic Concurrency Control with Versioning and when Hibernate throws Concurrency Update issue due to same row is being updated in two transaction then use one of below strategy
First Wins Strategy
Last Wins Strategy
Merge Conflicting Update Strategy
First Wins Strategy is not good solution as it leads to lost update and user will get frustrated that all his work is lost.
By Last Wins Strategy one of user will get error message that you are working on Stale data and start your transaction again . By this way also user can get frustrated due to fact that now again he need to restart operation from beginning but his changes will not lost.
Instead go with Merge conflicting Update Strategy, when Hibernate throws Stale object exception reload screen with new data and user will see updated result and allow him to proceed with latest data. In this user changes will not loss and user will not get error message , just his screen reloads with fresh data and he can decide whether to proceed or not .
You can take example any e-commerce site and you will get one of result of either Last Wins Strategy or Merge Conflicting Update Strategy. Two user can start to by one item but one of user will get message in last screen that item is not stock.

Proforma SalesInvoice doesn't show data from all tables

In the salesInvoice ssrs Report i have added a table called carTableEquipTmp which is not there by default, which I insert into along with the other tables(SalesinvoiceTmp and SalesinvoiceHeaderFooterTmp) in SalesInvoiceDP.InsertIntoSalesInvoiceTmp().
Even though my table carTableEquipTmp is getting successfully inserted into, the data doesn't show up on the report if i print a proforma report.
If i add test values to the carTableEquipTmp table in SalesInvoiceDP.processReport() they show up on the proforma invoice, but there's no way for me to get any parameters needed to set in the correct data into the table at this point. If i stop at this point in the debugger none of the data is present because processreport() is being called from a lower level in the code.
I think it might be a problem with maybe pack/unpack or that the proforma code runs from a server instance as the code run when it is proforma is quite different.
I can see that SalesInvoiceJournalPostBase.CreateReportData() creates an instance of salesInvoiceDP
salesInvoiceDP = new SalesInvoiceDP();
salesInvoiceDP.parmDataContract(salesInvoiceContract);
salesInvoiceDP.parmUserConnection(new UserConnection(true));
salesInvoiceDP.createData();
And that this might have something to do with it... but i still cant get the data i want in the carTableEquipTmp table.
So any idea on how to make Ax 2012 accept this new table i have added as it gets inserted into just like the other tables and there seems to be no problem...
I hope you guys can help.
The SalesInvoice report has two data classes you need to look at for the data provider, SalesInvoiceDP and SalesInvoiceDPBase. SalesInvoiceDPBase extends SrsReportDataProviderPreProcess, so there are a couple extra steps you need to take in order to add new datasources to the report.
In the salesInvoiceDP class, there is a method called useExistingReportData(), which re-inserts the pro-forma temp table data under a user connection, so the SrsReportDataProviderPreProcess framework will pick it up in your report. When the pro-forma process creates the report data, it doesn't insert with a user connection so it doesn't get added to the report. This method only gets called when the report is being run pro-forma.
You will need to add your temp table to this method, and follow the pattern for the other tables, so your code will look something like this:
//this is different from the buffer you insert your data with
CarTableEquipTmp localCarTableEquipTmp;
...
recordList = new RecordSortedList(tableNum(carTableEquipTmp));
recordList.sortOrder(fieldNum(carTableEquipTmp, RecId));
//You will need to add a field to relate your temp table
//to the current invoice journal, and insert it in
//InsertIntoSalesInvoiceTmp() if thats where you're inserting your table.
while select localCarTableEquipTmp
where localCarTableEquipTmp.JournalRecId == jourRecId
{
recordList.ins(localCarTableEquipTmp);
}
delete_from localCarTableEquipTmp
where localCarTableEquipTmp.JournalRecId == jourRecId;
recordList.insertDatabase(this.parmUserConnection());
This method re-inserts your data under the framework and deletes the original data. The data that was re-inserted will then get picked up by the framework and show in your report. If you open CarTableEquipTmp in the table browser, you will most likely see data still there from all the times you have tried running the report. This is why we have the delete_from operation after we re-insert the data. When data is inserted under a userConnection, it is automatically deleted when the report is finished
The other method you will want to modify is SalesInvoiceDP.setTableConnections(), and you will just need to add the following line:
CarTableEquipTmp.setConnection(this.parmUserConnection());
This will set the user connection for your table when running regular (not pro-forma). You will probably want to delete the data that is stored currently in your temp table using alt+F9 from the table browser.
Other than that it's all standard RDP stuff, but it sounds like you have that part working fine. Your temp table must be of type "Regular" for this to work.

LLBLGenPro + VB6 project - accessing new columns added to a typedlist

I have a program made in Visual Basic 6 which access data from a database (made with Microsoft SQL server management studio express 2000 then migrated to 2005) and puts all data into an immense GridView.
The views, typedlists, queries, etc... all have to go through LLBLGenPro, which is used from what i learned to regenerate the entire code of our program in case we need to add anything. The project on LLBL contains entities, typedlists and typedviews. I'm not a pro of LLBLGenPro and i'm just starting to discover it
I have to add two columns to the Gridview with two specific tables columns containing the information i need. So i went onto the database to modify the view i needed to get the required data (which now gives me the two more desired rows), then i loaded the database again in LLBLGenPro and made sure to check my new fields in the typedList that contains them. I regenerated the program, and
started the visual basic project. My columns appear in all the files where they should be, with the right names (the typedlist and the views referring to it). The classes now find 23 column indexes instead of 21. All seems fine for now.
The typedList is then imported into the main class:
Private _typedList As New DBSqlTypedList.MyClassNameTypedListTypedList
All the items from the table in the DB are already loaded correctly by the code using filters and appear in the program without problem. The typedlist we need (imported as _typedList) fills the data in the gridview (GridBT) with the following lines:
If isOpenSoftware Then
With Me.gridBT
.AutoGenerateColumns = True
.AlternatingRowsDefaultCellStyle = Nothing
.DataSource = _typedList
Now here's the problem: _typedList does not see my two news rows at all and they don't appear in the grid at all.
Typing _typedList.item(0).xxxx for example gives me access to all the rows that were already there but none of the two i added appear in it.
Did I forget something in LLBLGenPro?
Don't hesitate to tell me if you think i didn't send enough code or information!

Saving copy of old table entry to another table when updating table entry with SaveChanges()?

Im working on an online store project where I have already made it possible for an administrator to update different table entries via the store gui (like items, user profiles, orders etc). SaveChanges(); is used to save the changes.
Im currently trying to figure out how to make this work:
An entry in table "items" gets updated.
Before the entry in the table "items" gets updated, a copy of the old entry gets saved into a table named "history-items".
The copy that is saved to "history-items" preferably has a timestamp.
How would I go about doing this? (As you might tell, I just recently picked up visual studio, and am pretty new to everything)
Thank you.
There are atleast 3 ways to do this:
If you are using SQL Server 2008 or newer this is now built in functionality, see: http://msdn.microsoft.com/en-us/library/bb933994.aspx
If you opt not to use that then the simplest solution is to use database triggers.
If you want to do it in C# code, then you need to read the original values before saving, and save these original values to the history table. For reading original values see: How to get original values of an entity in Entity Framework?
I would go for option 1 if possible.

Current version of data in database has changed since user initiated update process

I have a Master Detail form in my Oracle APEX application. When I am trying to update data in this form, I am getting below error.
Current version of data in database has changed since user initiated
update process. current row version identifier =
"26D0923D8A5144D6F483C2B9815D07D3" application row version identifier
= "1749BCD159359424E1EE00AC1C3E3FCB" (Row 1)
I have cleared browser cache and try to update. But it not worked.
How can I solve this?
I have experienced similar problem where my detail records set has timestamp fields. By default master detail wizard creates the timestamp fields as date picker type fields. If you set the date format on these, it would resolve the issue.
This blog post tries to address this issue on a Tabular Form (I know that's not what the original issue was with, but thought it might be related). It says the same as #sangam does below.
Short version: If you have an updated field that's timestamp datatype, you should set a date/time format.
http://apexbyg.blogspot.com/2015/05/tabular-form-bug.html
My tabular form has a field that's timestamp datatype, but I had already set a date format, so this didn't help me.
Here's another possibility, which I discovered was the case in my application.
That would be if the data the original checksum was calculated on is truly different than the pre-update checksum calculation, due to a design-flaw in your query!
In my application, the source for one of the updateable fields was COALESCE(name_calced, name_preferred). In the source table, the person's name could already be loaded in the record by an external process and we save it to one field - name_calced. But the end-user can enter a preferred name, which we wanted to save to the name_preferred field. We wanted to initially populate the displayed, updateable tabular form field with name_calced, if one existed, or name_preferred if the user had already provided a preferred name. Then they could change that value and save it back to the database.
I finally discovered that the Save action threw the error message if name_calced was non-null, but name_preferred was null. I realized that the initial checksum was calculated based on name_calced, but the pre-update checksum was based on name_preferred, so the application thought someone had changed the value in the background and showed the error message.
What I don't understand is how this problem didn't show up in the past 3 years the application has been running in production!
My solution is to make the field source only on name_preferred, which immediately solved this problem. I also think the back-end process will also get changed to pre-populate that table field from name_calced, so the user always sees the base value, if there is one.
I just had this issue myself. Now, I realize that tabular forms are deprecated at this time, but I have an application that was developed beforehand and still uses them. This issue occurred and I had to get one of our big guns at Oracle to help me out. I do a lot of DB work and a decent amount of Apex development but I'm more of a Java, WebLogic, etc guy, and I really couldn't figure this one out.
In my case, it turned out to be really simple. One of the columns in my tabular form was a hidden field, generated via a sub query. Being hidden, this column is not editable by the user and should not be part of the MRU update. I had the field set to "Hidden Column (saves states)" and setting its type to "Hidden Column" fixed the issue. So, this leads to sub queries being executed in such a way as to change the checksum for the overall query before hitting submit (save), causing the error.
For those who are continuing to troubleshoot this, look at your query for every field that you have specified and note which columns are editable in the tabular form. All other fields should be set in a way that makes them not save state so that they are not part of the update.
I had this error when I had two update processes processing on submit.
My solution was to add a condition to both processing steps. I had forgotten to do this when I made an additional process for Button A, but I never updated Button B to limit it's behaviors.
Navigation:
Processing -> Processes -> [Your Process Name] -> Server-side Condition -> When Button Pressed = [Your button Name]
In my case I had a column from a secondary table that was not set as Query Only and was being updated! The error would occur trying to save a column not in the table being updated. It took me half a day to figure it out (the column names were the same).
Set your Link column hidden to display only in the form.
Set "Send On Page Submit" to 'No' or disable the link column that is your primary key ( Rownum/rowid/id etc).
Hope it will work for you.
I have noticed this error comes when I was working Tabular Form and has disabled one of the form operations i.e. by setting server-side condition to "Never" for add, apply changes (submit) buttons
When I have restored back to its original state, it worked as expected.
In case you have to hide Add/Update button, use some other option.
https://compknowledgebase.blogspot.com/2018/12/oracle-apex-error-current-version-of.html

Resources