How to update items in CrudPanel - vaadin

In a CrudPanel I have the need to update some items (not through the CRUD dialog). Something like this:
#Transactional
...
instance.setSomeAttribute(newValue);
return savedInstance = instanceRepository.save(instance);
Calling refreshAll on the dataProvider after the update produces the warning Got an RPC for non-existent node: xxxx. Also I guess it is a little expensive to refresh all items if just one changed.
Calling the specific refresh item, on the other side, refreshItem(instance), gives Object of class [...MenuItem] with identifier [xxxx]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
I also tried to pass newInstance to refreshItem, same result.
Can somebody indicate how to proceed?

Check equals and hashCode that they don't contain fields that may have changed when you call refreshItem.

Related

Why Hybris modelService.save() doesn't work inside the ifPresent() method?

private void doSomething(someProcessModel process){
CustomerModel customer = process.getCustomerModel();
customer.getFoos().stream()
.filter(foo -> foo.getCountryCode().equals(process.getCountryCode()))
.findFirst()
.ifPresent(foo -> {
if(foo.getSomeNumber() == null){
foo.setSomeNumber("1234567");
modelService.save(foo);
}
});
}
As seen in the code snippet above, I have a 'CustomerModel' that has an attribute 'Foos'. It's a one-to-many relationship. As you can see I have done some filtering and in the end, I want to update the value of 'someNumber' attribute of 'Foo' if it is null. I've confirmed that everything is working as the "someNumber" attribute's value is updated during the debugging. It doesn't save at all as I have done my checking in the HMC. I have also validated that the Interceptor doesn't have any condition that would throw an error. There is nothing being shown in the log either.
I am wondering is it a legal approach to do the "modelService.save()' inside the 'ifPresent()' method? What could be the possible issue here?
I have found the root cause now as I have face the same issue again.
Context to my original question
To give more context to my original question, the #doSomething method resides in a Hybris Business Process action class and I have ended the action prematurely while I am debugging it (by stopping the debugging) once the #doSomething method is ran.
Root cause
The mentioned problem happened when I was debugging the action class. I assumed that the ModelService#save will persist the current state of the business process once it has been ran. However, the Hybris OOTB business process will do a rollback if there is any error (and I believe it was caused by me stopping the debugging half-way).
SAP Commerce Documentation:
All actions are performed inside their own transaction. This means that changes made inside the action bean run method are rolled back in case of an error.
Solution
Let the action runs completely!
Good to know
Based on the SAP Documentation and this blog post, there will be times that we will need to bypass a business process rollback even though there is an exception being thrown and there are ways to achieve that. More info can be found in this SAP Commerce Documentation and the mentioned blog post.
However, in some circumstances it may be required to let a business exception reach the outside but also commit the transaction and deal with the exception outside. Therefore, it is possible to make the task engine not roll back the changes made during a task which failed.
You have to be cautious with a list in models as they are immutable, you have to set the whole new list. Also you called save only on a particular model, which changes its Jalo reference, that's why your list is not updated. Mutating stream and collecting it in the end will create new list that's why you can stream over the list directly from the model.
private void doSomething(someProcessModel process){
CustomerModel customer = process.getCustomerModel();
ArrayList<FooModel> foos = doSomethingOnFoos(customer.getFoos());
customer.setFoos(foos);
modelService.saveAll(foos, customer);
}
//compare the value you know exists with something that might be NULL as equals can handle that, but not the other way around
private ArrayList<FooModel> doSomethingOnFoos(ArrayList<FooModel> fooList) {
return fooList.stream()
.filter(Objects::nonNull)
.filter(foo -> process.getCountryCode().equals(foo.getCountryCode()))
.filter(foo -> Objects.isNull(foo.getSomeNumber()))
.map(foo -> foo.setSomeNumber(1234))
.collect(toList());
}

why does save() not save the data and save(flush: true) is required?

RaceRegistration domain has embedded raceParticipant and raceParticipant has a field bibNumber which is Integer.
I have a method for nulling out all bibNumbers of registrations but without flush:true in save, the nulling out of bibs dont work. The bibs are not set to null.
def nullifyBibNumbers(Long id){
...
def regss = RaceRegistration.createCriteria().list(){
eq('compositeEvent', event)
}
regss.each{ r ->
r.raceParticipant.bibNumber = null
r.save()
}
render "Bibs resetted!"
}
If i add flush:true then the bibs are set to null.
regss.each{ r ->
r.raceParticipant.bibNumber = null
r.save(flush: true)
}
I am wondering why you need flush in order for the value to be set to null? I am guessing the problem is with regard to how i am obtain the registration list using createCriteria(). I appreciate any help in this dilemma i am facing. Thanks!
As you probably figured out, save(flush: true) forces Hibernate to write any pending changes to the database. Without the explicit flush, you're relying on a Hibernate transaction to automatically flush when the transaction commits.
The reason only an explicit flush is working for you is because you're not calling save() within a transaction.
The cleanest fix is to create a Grails service, put nullifyBibNumbers() in it, and make the service transactional. That will cause nullifyBibNumbers() to get wrapped in a transaction so that you can use save() without an explicit flush.
If nullifyBibNumbers() is already in a service, you can add #Transactional to the service class, just keep in mind that it will make all methods (perhaps only the public ones?) transactional. Having said that, you can use #NotTransactional on a method to disable transactions.
The value is null in your domain object. But you are talking about null in the database, I guess?
It shouldn't matter. This is basic ORM. As a developer you don't care about when the flush is done. Typically this would be at the end of a transaction. The ORM will then flush all of the changes for that transaction at once.
It works on what is called the first-level cache during the transaction, and tries to avoid going to the db until it is explicitly requested (flush:true) or required (end of transaction).
Without the using of
save(flush: true)
The object will not be persisted immediately.
You can follow the documentation link and see the following information:
The save method informs the persistence context that an instance
should be saved or updated. The object will not be persisted
immediately unless the flush argument is used.
Related to the null issue you are facing make sure that the following condition are met.
The save method returns null if validation failed and the instance was
not persisted, or the instance itself if successful.
You do not need the flush in order for the value to be set to null.
The flush only care of a quick update of the database.
ok i fixed this problem using HQL instead of domain saves. Still i would appreciate why save() didnt work and save(flush:true) saved the data. Thanks!
RaceRegistration.executeUpdate("update RaceRegistration set raceParticipant.bibNumber = null where compositeEvent.id = :ev", [ev: id])

which is the difference betwwen this two ways to refresh the dbContext?

I am using EF 4.4 and I would like to update many entities, but some other user can modified many of the entities that the first user is modified. So I get a concurrency exception. Other case is that the first user tries to add many new registers and other user added some of them meanwhile. So I have an exception that exists some of the registers (unique constraint).
I would like to ensure that the first user finish his operation add only the registers that does no exists yet (add all his entities except the entities that are added by the second user).
To do that, I need to update the entities in my dbContext so I see that there at least two options.
First, in the catch when I capture the update exception, I can do:
ex.Entries.Single().Reload();
The second option is:
myContext.Entry<MyTable>(instance).Reload();
I guess that the second option only refreshes the entity that I use as parameter, but if the problem is that I need to refresh many entities, how can I do that?
What really does the first option, Single().Reload?
When you do
ex.Entries.Single().Reload();
you are sure that the offending entity is refreshed. What is does is taking the one and only (Single) entity from the DbUpdateConcurrencyException.Entries that could not be saved to the database (in case of a concurrency exception this is always exactly one).
When you do
myContext.Entry(instance).Reload();
You are not sure that you refresh the right entity unless you know that only one entity had changes before SaveChanges was called. If you save an entity with child entities any one of them can cause a concurrency problem.
In EF 6.x (6.1.3), below code will let you find all the changes; the way you asked in your question!
try
{
var listOfRefreshedObj = db.ChangeTracker.Entries().Select(x => x.Entity).ToList();
var objContext = ((IObjectContextAdapter)your_db_context).ObjectContext;
objContext.Refresh(System.Data.Entity.Core.Objects.RefreshMode.ClientWins, listOfRefreshedObj);
await db.Entry(<yourentity>).ReloadAsync();
return Content(HttpStatusCode.<code>, "<outputmessage>"); ;
}
catch (Exception e)
{
return Content(HttpStatusCode.<code>, "<exception>");
}
Explaination:
Query Entries in the ChangeTracker and store them in a list
var listOfRefreshedObj = db.ChangeTracker.Entries().Select(x => x.Entity).ToList();
Next is to refresh the context. In some cases (row is removed etc.), this will throw an exception which you can catch. RefreshMode.ClientWins tells EF to accept all client units as modified when next update occurs. In some cases, you might want to prompt the users with the changes and let them decide. RefreshMode Enumeration. An example is here ObjectContext.Refresh Method Example
objContext.Refresh(System.Data.Entity.Core.Objects.RefreshMode.ClientWins, listOfRefreshedObj);
You're probably doing this whole thing after you receive DbUpdateConcurrencyException anyways!

Why am I getting a "Unable to update the EntitySet because it has a DefiningQuery..." exception when trying to update a model in Entity Framework?

While updating with the help of LINQ to SQL using Entity Framework, an exception is thrown.
System.Data.UpdateException: Unable to update the EntitySet 't_emp' because it has
a DefiningQuery and no <UpdateFunction> element exists in the
<ModificationFunctionMapping>
The code for update is :
public void Updateall()
{
try
{
var tb = (from p in _te.t_emp
where p.id == "1"
select p).FirstOrDefault();
tb.ename = "jack";
_te.ApplyPropertyChanges(tb.EntityKey.EntitySetName, tb);
_te.SaveChanges(true);
}
catch(Exception e)
{
}
}
Why am I getting this error?
The problem was in the table structure. To avoid the error we have to make one primary key in the table. After that, update the edmx. The problem will be fixed
Three things:
Don't catch exceptions you can't handle. You're catching every exception possible, and then doing nothing with it (except swallowing it). That's a Bad Thing™ Do you really want to silently do nothing if anything goes wrong? That leads to corrupted state that's hard to debug. Not good.
Linq to SQL is an ORM, as is Entity Framework. You may be using LINQ to update the objects, but you're not using Linq to SQL, you're using Entity Framework (Linq to Entities).
Have you tried the solution outlined here? The exception you posted is somewhat cut off, so I can't be sure it's exactly the same (please update your post if it isn't), and if it is the same, can you comment on whether or not the following works for you?
"[..] Entity Framework doesn't know whether a given view is updatable
or not, so it adds the <DefiningQuery> element in order to safeguard
against having the framework attempt to generate queries against a
non-updatable view.
If your view is updatable you can simply remove the <DefiningQuery>
element from the EntitySet definition for your view inside of the
StorageModel section of your .edmx, and the normal update processing
will work as with any other table.
If your view is not updatable, you will have to provide the update
logic yourself through a "Modification Function Mapping". The
Modification Function Mapping calls a function defined in the
StorageModel section of your .edmx. That Function may contain the
name and arguments to a stored procedure in your database, or you can
use a "defining command" in order to write the insert, update, or
delete statement directly in the function definition within the
StorageModel section of your .edmx." (Emphasis mine, post formatted for clarity and for Stack Overflow)
(Source: "Mike" on MSDN)
But You can Set primary Key in Model if use MVC Asp.net
Just Open model.edmx in your table ,go to your field property and set Entity Key = True

troubleshooting a NullPointerException in grails

preface note: I'm just starting to learn Grails, so I'm sure there are many other problems and room for optimization.
I've got two domains, a parent (Collection) and child (Event), in a one-to-many mapping. I'm trying to code an integration test for the deletion of children. Prior to the code in question, I've successfully created a parent and three children. The point where I'm having problems is getting a single child in preparation to delete it. The first line of my sample code is only there because of my rudimentary attempt to troubleshoot.
// lines 95-100 of my EventIntegrationTests.groovy file
// delete a single event
assertEquals("2nd Event", event2.title) // passes
def foundEvent = Event.get(event2.id) // no apparent problems
assertEquals("2nd Event", foundEvent.title) // FAILS (line #98)
foundEvent.delete()
assertFalse Event.exists(foundEvent.id)
The error message I'm getting is:
Cannot get property 'title' on null object
java.lang.NullPointerException: Cannot get property 'title' on null object
at edu.learninggrails.EventIntegrationTests.testEventsDelete(EventIntegrationTests.groovy:98)
What should my next troubleshooting steps be? (Since the first assertEquals passes, event2 is clearly not null, so at this point I have no idea how to troubleshoot the failure of the second assertEquals.)
This is not evident from the code: did you persist event2 by calling save()? Get will try to retrieve it from the persistent storage (the in-memory database for example) and if the event wasn't saved, the retrieved instance will be null.
If you did save it, did the save go through OK? Calling event.save() will return false if there was something wrong while saving the item (like a validation error). Lastly, you might try calling event.save(flush:true) in case the Hibernate session doesn't handle this case as you might expect (I'm not entirely sure about this one, but it can't hurt to try).
Try to print or inspect the event2.id on line 97 and check if you actually have an id, if so check if you actually get an Event object on line 97.
I dont think you saved the parent and its children successfully. after you save, you should make sure that every object that was persisted has a non null id, in your test.
What you are seeing is you created the event2 with a title, but didnt save it. It passes the first assertion because you created it. When you do the get, null is returned because your save failed.
in general for DAO integration tests i do the following
Setup -- create all objects Ill use in the test.
Save -- assert that all ids on saved objects are NOT null.
Clear the hibernate session -- this is important because if you don't do it, objects can be in the session from the previous operations. In your real world scenario, you are probably going to start with a find, i.e. an empty session. In other words, you are not going to start with anything in the session. If you are you need to adjust this rule so that the session in the test, when you start the actual testing part, is the same as the session of the code in the wild
Load the objects on which you want to operate and do what you need to do.

Resources