FND_RECORD_CHANGED_ERROR on OAF page - oracle-adf

I read the stack-trace and found that the error comes from oracle.jbo.EntityImpl.lock(). I read that is caused by RowInconsistentException. So the problem is data difference between my database and OAF page.
I put a break-point in the beginning of the method. I saw three interesting child objects: mData, mOrigData and mChanged. I saw that in my case mData content is identical to the database and mOrigData differes. How should I interpret it?

I found that mData means state before OAF operations, and mOrigData - state afterwards. mChanged contains ids of changed attributes. In my case I already had a non-null value in the database (non-null in mData) but on the page I was losing that value and tried to put null into the database (null in mOrigData). The framework decided that it was wrong.
I also had another case: updated_at attribute in the database was larger than in the mData object. It turned out that the database processed the row in the background after 2 seconds, but OAF read the row earlier. When I was trying to commit, OAF found that its state is older in the database and threw the same error.

Related

Entity Framework 6 query generates NullReferenceException

Edit: This is not a problem with ignorance of basic programming (such as trying to dereference a null object reference).
Edit: Added the stack trace from EF within Linqpad.
Using EF6, I have a very simple query :
var menu = dbcontext.Tree.Where(t => t.Left > 2 && t.Right < 10).ToList();
This worked right up until it mysteriously stopped. dbcontext.Tree is a view in SQL Server 2012. Using Linqpad5, I get the results I expect using its built-in connection. Setting up an EF connection to my project, I get the NRE. Checking the SQL, I can copy and paste that into a SQL query window and get the proper results. I get an NRE without the Where call, also.
I've tried updating my model from database to refresh anything. I've tried removing the view from the model and updating. I've tried deleting the model entirely and recreating it. I've restarted Visual Studio AND my computer. I get the same NRE for the query. I don't know what else I can try, and this NRE makes no sense to me at all, given I get the results I expect using everything but EF. I'd chalk it up to a bug with EF if I didn't see it working previously.
Has anyone dealt with this? Searching online for this specific set of circumstances has produced nothing.
Stack Trace :
at System.Data.Entity.Core.EntityKey.AddHashValue(Int32 hashCode, Object keyValue)
at System.Data.Entity.Core.EntityKey.GetHashCode()
at System.Collections.Generic.GenericEqualityComparer`1.GetHashCode(T obj)
at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
at System.Data.Entity.Core.Objects.ObjectStateManager.TryGetEntityEntry(EntityKey key, EntityEntry& entry)
at System.Data.Entity.Core.Objects.ObjectStateManager.FindEntityEntry(EntityKey key)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
The problem is that your Model (Tree in your example above) has one ore more properties that are not nullable (and possibly also marked as not nullable in the mapping) but the corresponding column in the data store is nullable. This exception would only manifest itself as soon as there was a record being retrieved that had a null value for one of those column(s).
Model fix - When updating the model be sure to use Nullable<T> or ? for nullable value types and if you have mappings defined (either via attributes or in types that inherit EntityTypeConfiguration) also specify that the property is optional there.
Data store fix - Alternatively change the data store schema and data to align it with what is expected in the model.

Oracle ADF web browser refresh button gets old page

i'm developing an ADF application. I have a problem. My Jdev version 11.1.2.3.0.
So, For example i have an URL like this "http://www.hohoho.com/view/index.xhtml?_adf.ctrl-state=ju9lnu5ld_3"
In this page i have a table gets value from DB. For example again, i changed some rows in DB browser, and clicked the web browser's refresh button. But new results doesnt get!. For example i remove the "?_adf.ctrl-state=ju9lnu5ld_3" and enter url, this gets new results. How can handle this situation. I need that when an user clicked the refresh button, last result must be fetched. I think it is based on ADF state. How can handle this situation.
Solution
Thanks Andread, mysql's autocommit property default value is true, not false :) but i was using it false. I've solved the problem like yours, but my own solution so cool :) I've only overried the clearCache() method. And it solved the problem.
public void clearCache() {
getDBTransaction().commit(); // added
super.clearCache();
}
The results from the query are cached in the middle tier. This is the reason why updates to the database which are applied through a different channel than through your application are not reflected when the page reloads.
I am using JDeveloper 11.1.1.7. Setting the "CacheResults" property on the Iterator to false solved this issue (go to the "Bindings" tab of your page or page fragment which contains the table, select the Iterator Executable for your table data, and in the Property Inspector at the "Advanced" section, set "CacheResults" to "false").
In terms of XML, the iterator definition in the PageDef.xml file should look like
<iterator id="TestIterator" Binds="TestView1"
DataControl="AppModuleDataControl" RangeSize="25"
CacheResults="false"/>
There seem to be some additional approaches to solve this, probably this was necessary in earlier JDeveloper versions:
http://technology.amis.nl/2012/06/18/notifying-adf-applications-of-database-changes-fast-and-lean-using-database-query-result-change-notification-part-one/
http://radio-weblogs.com/0118231/stories/2005/06/16/whyIsntRefreshingTheBrowserPageEnoughToRefreshTheDataDisplayed.html
ADDENDUM 03-DEC-2012
OP uses MySQL. With MySQL, setting the CacheResults property is required, but not sufficient. By default, MySQL runs with autocommit=false which has the side effect of using the isolation level REPEATABLE READ. A SELECT implicitly opens a transaction, and subsequent SELECTs return the same result. The Oracle RDBMS uses READ COMMITTED by default, so that data inserted and committed in one session is returned by SELECT in a different session.
One solution to get around this in ADF is to create an implementation class for the View Object, override executeQueryForCollection() and commit the transaction before executing the query:
protected void executeQueryForCollection(Object object, Object[] object2, int i) {
getApplicationModule().getTransaction().commit();
super.executeQueryForCollection(object, object2, i);
}
Please use this carefully and review your actual isolation level requirements to make sure that you do not unintentionally commit data by a browser refresh. Another drawback of this solution is that it is not portable between Oracle RDBMS and MySQL.
See https://github.com/afester/StackOverflow/tree/master/AdfRefresh for an SSCCE.

Problem with checking an original database record with an edited one

I am having problems saving database records using Linq in visual studio 2010 and sql server 2008.
My problem is that when I am editing some records I sometimes check the original database record for validation purposes, only the original entry seems to be updated in real time - I.e. it is already exactly the same as the edited record, before I have submitted the changes!
Could anyone suggest an effective method of coping with this? I have tried using a 2nd database connection or a 2nd data repository to call the original record from the db but it appears to be already changed when I debug it.
public void SaveobjectEdit(object objectToEdit)
{
object originalObject = GetobjectById(objectToEdit.Id);
if (originalObject.objectStatus != objectToEdit.objectStatus)
{
originalObject.objectStatus = objectToEdit.objectStatus;
}
SaveChanges();
}
The save changes just calls _db.SubmitChanges(); by the way
Has no one got any ideas for the above question?
I hope I was clear - for validation purposes I would like to compare an original database record with one that I am editing. The problem is that when I edit a record and then attempt to retrieve the original record before saving - the original record is exactly the same as the edited record.
If you're trying to retrieve the original record in code, from the same 'context' using the same access method, then it will contain the updated object. Rather than ask why you're doing this or what you're trying to achieve, I'll instead explain how I understand the data context / object context to work (in a very loose and vague fashion).
The context is something like an in-memory representation of your database, where everything is lazy-loaded. When you instantiate the context you're given an object which represents your data model (of course it may not be a 1-1 representation, and can contain various abstractions). Nothing is loaded into the context until necessary; any queries you write stay as queries until you peer in their results. When you access an item (e.g. GetobjectById(objectToEdit.Id)) the item is loaded into the context from the database and you can get and set its properties at your leisure.
Now, the important part: When you access an item, if it has already been loaded into the context then that in-memory object is returned. The context doesn't care about checking changes made; the changes won't be persisted to the database until you submit, but they remain in memory.
The way to refresh the in-memory objects is to call the Refresh method on the context. Try this test:
using (var db = new MyObjectContext())
{
var item = db.Items.First();
item.Name = "testing this thing";
Console.WriteLine(db.Shifts.First().Name);
db.Refresh(System.Data.Objects.RefreshMode.StoreWins, db.Items);
Console.WriteLine(db.Shifts.First().Name);
}
I believe this pattern makes a lot of sense and I'm not sure it could work any other way. Consider this:
foreach (var item in db.Items)
{
item.Name = "test";
}
Assert(db.Items.All(item => item.Name == "test"));
Would you want the Assert to fail? Should those items be reloaded? I don't believe so. I'm looking at the items in my context, not in the database. I'm not checking whether items in the database have been updated, but instead that I've updated all the items in the context of my code.
This is a good reason why I don't use MyObjectContext db - it is not a 'db' or a database connection. It's a context within which I can change whatever I want, so I name it such: MyObjectContext context.

How does the LINQ RefreshMode work?

In case of conflict, I need to overwrite the values in the database with my changes . I found the following article on MSDN that explains how to resolve conflicts using the RefreshMode:
http://msdn.microsoft.com/en-us/library/system.data.linq.refreshmode.aspx
I decided KeepCurrentValues makes sense for my requirement and I also found this page with an example for this mode:
http://msdn.microsoft.com/en-us/library/bb399421.aspx
However when I implemented this the values from the database always overwrote my changes. I tried changing the RefreshMode to OverwriteCurrentValues and KeepChanges and each time the values from the database were saved. My approach was to manually change values in the database while in debug mode in VisualStudio. The code in VS is:
[MyDataContext] db = new [MyDataContext]();
try
{
[MyLINQType] old = (from o in db.[MyLINQType] where o.ID=1 select o).Single();
old.IntField = 55;
// This is where I change the IntField value manually in the database in
// debug mode to generate the conflict.
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException)
{
db.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues);
}
I know that the conflict appears but every time, no matter how I change the RefreshMode, the value 55 is never saved and the changes that I made manually in the database are kept. Is there some trick to achieve the desired result? I have tried generating the conflict from inside the code at first and that didn't work as expected either. Maybe I didn't understand how the RefreshMode should work. Any ideas are welcome.
You just need to call SubmitChanges again...
catch (ChangeConflictException)
{
db.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues);
db.SubmitChanges();
}
The conflict resolution method determines the state of the DataContext and not the underlying database.
KeepCurrentValues means keep all values as they are currently in the DataContext, which means the next call to SubmitChanges will save any changes made by the user, but it will also overwrite any changes made by other users after the data was loaded by the current user.
KeepChanges means keep only the values that have been changed since being loaded into the DataContext, which means the next call to SubmitChanges will save any changes made by the user and will preserve any changes made by other users. And, if another user changed the same value as the current user, the current user's change will overwrite it.
OverwriteCurrentValues means update the DataContext with the current database values, which means that all changes made by the current user will be discarded.
Before changing data, you refresh your object by overwriting from Db :
[MyLINQType] old = (from o in db.[MyLINQType] where o.ID=1 select o).Single();
Db.Refresh(RefreshMode.OverwriteCurrentValues, old);
old.IntField = 55;
db.SubmitChanges(ConflictMode.ContinueOnConflict);

How can I retrieve latest from database using NHibernate after an update?

Here is the scenario:
I have a winforms application using NHibernate. When launched, I populate a DataGridView with the results of a NHibernate query. This part works fine. If I update a record in that list and flush the session, the update takes in the database. Upon closing the form after the update, I call a method to retrieve a list of objects to populate the DataGridView again to pick up the change and also get any other changes that may have occurred by somebody else. The problem is that the record that got updated, NHibernate doesn't reflect the change in the list it gives me. When I insert or delete a record, everything works fine. It is just when I update, that I get this behavior. I narrowed it down to NHibernate with their caching mechanism. I cannot figure out a way to make NHibernate retrieve from the database instead of using the cache after an update occurs. I posted on the NHibernate forums, but the suggestions they gave me didn't work. I stated this and nobody replied back. I am not going to state what I have tried in case I didn't do it right. If you answer with something that I tried exactly, I will state it in the comments of your answer.
This is the code that I use to retrieve the list:
public IList<WorkOrder> FindBy(string fromDate, string toDate)
{
IQuery query = _currentSession.CreateQuery("from WorkOrder wo where wo.Date >= ? and wo.Date <= ?");
query.SetParameter(0, fromDate);
query.SetParameter(1, toDate);
return query.List<WorkOrder>();
}
The session is passed to the class when it is constructed. I can post my mapping file also, but I am not sure if there is anything wrong with it, since everything else works. Anybody seen this before? This is the first project that I have used NHibernate, thanks for the help.
After your update, Evict the object from the first level cache.
Session.Update(obj);
Session.Evict(obj);
You may want to commit and/or flush first.
what about refresh? - see 9.2. Loading an object of the docs:
"sess.Save(cat);
sess.Flush(); //force the SQL INSERT
sess.Refresh(cat); //re-read the state (after the trigger executes)
"

Resources