Ignore an Ebean Version in certain situations - java

I'm using a Version field with Ebean, in Play Framework 2.2, but in certain situations I would actually rather have the version of an object not be updated. Is this at all possible?
So someone has an account on my website and they're looking at a post of another user. If the user updates that post, it's not automatically reloaded in the frontend. Please don't suggest I do this to solve the problem, I can't do it that way.
The problem is when a user gives the post a rating, the PUT call is refused if the user updated the post recently.
Is there a way to force Ebean to ignore the version field in specific situations like this?

Please don't suggest I do this to solve the problem, I can't do it that way.
LOL, nobody's gonna to suggest it to you :)
Custom statement should avoid updating the version:
SqlUpdate update = Ebean.createSqlUpdate("UPDATE post set likes = likes+1 where id = :id");
update.setParameter("id", post.id).execute();
(tested it, works as required)

As an alternative approach to using SqlUpdate in Ebean 4.x you can use 'stateless updates'. Note that for the counter = counter + 1 use case SqlUpdate is still a better fit.
Customer customer = new Customer();
customer.setId(42);
customer.setName("Please update the name")
// customer.setVersion(2) ... not setting the version property
// perform stateless update (and the version property was not set)
Ebean.update(customer);
// effectively results in:
update customer set name = 'Please update the name' where id = 42

Related

Flexible search is asking for session country while called from REST api

I have a code which executes a flexible search. When i am calling that code locally to search data it gives expected output but when I try to call it using REST API (Through controller) it gives error as could not translate value expression 'session.currentCountry' but i am not even using session or session country anywhere in flexible search. what can be issue?
here is code
query
select {rr.pk} from {returnrequest as rr join order as r on {r.pk} = {rr.order} join orderstatus as os on {r.status}={os.pk} join basestore as bs on {bs.pk}={r.store} join returntype as rt on {rr.returntype} = {rt.pk} join paymentmode as pm on {pm.pk}={r.paymentmode} join returnstatus as rs on {rs.PK}={rr.status}} where {os.code} NOT in ('PENDING_PAYMENT','ON_VALIDATION', 'CREATED', 'IN_PROGRESS', 'ORDER_SPLIT','CANCELLED') and {rr.creationtime} >= ?returnCreationDateFrom and {rr.creationtime} < ?returnCreationDateTo and {bs.uid} in (?market) and {rt.code} in (?returnType) and {pm.code} = 'SplittedPaymentMode' and {rr.totalRefund} != 0.0 and {rs.code}!='RECEIVED' group by {rr.pk} ";
code
FlexibleSearchQuery query = new FlexibleSearchQuery(flexiQuery.toString());
query.addQueryParameter("market", market);
query.addQueryParameter("returnType", returnType);
query.addQueryParameter("returnCreationDateTo", DateUtils.addDays(returnCreationDateTo, 1));
query.addQueryParameter("returnCreationDateFrom", returnCreationDateFrom);
SearchResult<ReturnRequestModel> results = search(query);
same flow is running properly in local but giving issues in remote instace.
here is error
ERROR PaymentWsController de.hybris.platform.servicelayer.search.exceptions.FlexibleSearchException: could not translate value expression 'session.currentCountry'
19:37:31.834 [hybrisHTTP6] ERROR de.hybris.platform.jalo.flexiblesearch.FlexibleSearch - Flexible search error occured...
This error coming from research restriction. It looks your user hasn't got some session variables and a restriction try to use it. You can check this question answer.
The issue is that you have a SearchRestriction, Search Restriction is a set of rules which is applied on Flexible Search Query in order to limit the search results or to filter search results based on specific conditions.
You can see SearchRestrictions in Backoffice -> System -> Personalization, find the related one that adds session.currentCountry to your flexible search and either disable it or use impersonationService to execute your query inside a context with a site.
Hope this helps
Although others answers on the post are correct I just want to add my answer which helped to solve the issue.
The issue was with search restriction.
I just set current user as admin to bypass the restrictions. i.e.
userService.setCurrentUser(userService.getAdminUser());
I just added it before executing the search and error got resolved.
we can also set user as admin in flexiquery itself so that search restrictions can be avoided.
here is how.
query.setUser(userService.getAdminUser());
so both ways it can be done.

Retrieving full objects from a query done via Bolt protocol

In Neo4J, I want to use the bolt protocol.
I installed the 3.1 version of Neo4J.
I my Java project, that already works well with normal HTTP Rest API of Neo4J, I integrate with Maven the needed drivers and achieve to perform request with BOLT.
The problem is everywhere you make a search about bolt they give example like this one :
MATCH (a:Product) return a.name
But I don't want the name, I want all the data of all product, what ever i know or not before what are these columns, like here:
MATCH (a:Product) return * --> here I retrieve only the ids of nodes
I found there https://github.com/neo4j-contrib/neo4j-jdbc/tree/master/neo4j-jdbc-bolt we can "flatten" the result but it seems to not work or I didn't understand how it works:
GraphDatabase.driver( "bolt://localhost:7687/?flatten=-1", AuthTokens.basic( "neo4j", "......." ) );
I put the ?flatten=-1 at the end of my connection address... but that changed nothing.
Anyone can help? Or confirm it's not possible or not working ?
Thanks
Ok I understood my error, I didn’t dig enough in the object returned. So used to have a JSON formatted response, I didn’t see that I have to search in the StatementResult object to find the wanted object with its properties. In fact Eclipse in the “expressions” shows “in fly” only the ids, but inside the object data are there.
Record oneRecord = rs.next();
String src = oneRecord.get("m").get("source");
That way I can reconstruct my object

Spring JDBCTemplate Always Throws QueryTimeOutException

This is something that I've been scratching my head with - especially since it's infuriating to deal with.
Consider the following code:
String query = "UPDATE ORDERS SET VOLUME=?,CONTRACT_ID=?,PROJECT_ID=?,WORKSITE_ID=?,DROPZONE_ID=?,DESCRIPTION_ID=?,MANAGER_ID=?,DELIVERY_DATE=?,REVISION=REVISION+1) WHERE ID=?";
jdbcTemplate.update(query, orderEntity.getVolume(), orderEntity.getContractNo(), orderEntity.getProjectID(), orderEntity.getWorksiteID(), orderEntity.getDropzoneID(), orderEntity.getDescriptionID(), orderEntity.getManagerID(), orderEntity.getDeliveryDate(), id);
We can see that the SQL query is incorrect - and will therefore throw some SQL error but one might have missed that. Spring will (for me) throw a QueryTimeoutException in response to this. I'm sort of okay with that but it's not helpful.
Now let's try
String query = "INSERT INTO ORDERS(ID,REISION,CONTRACT_ID,PROJECT_ID,WORKSITE_ID,DROPZONE_ID,DESCRIPTION_ID,MANAGER_ID,VOLUME,DELIVERY_DATE) VALUES(?,?,?,?,?,?,?,?,?,?)";
jdbcTemplate.update(query, id, revision, etc);
Another spelling mistake that's easily missed - REVISION is misspelled as REISION) Spring throws another QueryTimeoutException again. This now means that if I get that exception I don't actually know what it is. Is it a syntax error? Is it a column spelling error? Is it the (much harder to notice) fact that the foreign key constraint not being followed?
While debugging, this is quite possibly the most infuriating thing ever - all I know is that my query failed to run. How can I get something useful? Is there something I've not added to my pom.xml file?
EDIT:
Here's a nicer example. I have a DESCRIPTIONS table, with an ID, REVISION and TEXT column. All of those are marked as not being nullable.
DescriptionEntity descriptionEntity = new DescriptionEntity("newDesc", 1, null);
String query = "INSERT INTO DESCRIPTIONS (ID,REVISION,TEXT) VALUES(?,?,?)";
jdbcTemplate.update(query, descriptionEntity.getID(), 1, descriptionEntity.getText());
That will also throw a query timeout exception, when running the query in mysql gives me ERROR 1048 (23000): Column 'TEXT' cannot be null
This is, to put it politely, a bit of a pain.
It's not a spelling mistake in the first example, as you left out the opening paren. I would say this isn't an issue with Spring or JDBC, but rather your DB is trying to process the SQL, waiting for more input or something, and never returning.
In the second one, I am not sure what you are talking about since I don't know the table design. I have to assume what you mean is ID is not unique? Again, I wouldn't blame Spring or JDBC, maybe the drive, most likely the database server.
Keep in mind, in a lot of cases, the way SQL is handled in the user Client UI is not the same as how it gets handled through JDBC. For instance, in SQL Server the SQL is set as a string, the passed in parameters set as variables, and it uses sp_executesql() to run it. I discovered that when I had a report that ran PERFECTLY fine through SQL Studio Manager client, but blew up when I ran it live because the query plan optimizer took a different path due to the differences in how the SQL was ran.
This is quite possibly the most stupid error I've ever come across: the issue was in how Maven resolved all the dependencies.
The requirement for Spring Security was placed before the JDBC requirement. That made Spring Security pull down org.springframework:spring-tx:jar:3.0.7.RELEASE:compile which satisfied the dependency for JDBC. Moving the JDBC requirement up meant JDBC pulled down org.springframework:spring-tx:jar:3.2.2.RELEASE:compile.

OptimisticLockException with Ebean/Play

I have a Play 2.1.3 Java app using Ebean. I am getting the OptimisticLockException below.
[OptimisticLockException: Data has changed. updated [0] rows sql[update person
set name=? where id=? and email=? and name=? and password is null and created=?
and deleted is null] bind[null]]
I understand that it is trying to tell me the record has changed between when I read it and when I tried to write it. But the only change is happening in this method.
public void updateFromForm(Map<String, String[]> form) throws Exception {
this.name = form.get("name")[0];
String password = form.get("password")[0];
if (password != null && password.length() != 0) {
String hash = Password.getSaltedHash(password);
this.password = hash;
}
this.update();
}
Am I doing this wrong? I saw similar logic in zentasks. Also, should I be able to see the the values for the bind variables?
UPDATE: I am calling updateFromForm() from inside a controller:
#RequiresAuthentication(clientName = "FormClient")
public static Result updateProfile() throws Exception {
final CommonProfile profile = getUserProfile();
String email = getEmail(profile);
Person p = Person.find.where().eq("email", email).findList().get(0);
Map<String, String[]> form = request().body().asFormUrlEncoded();
if (p == null) {
Person.createFromForm(form);
} else {
p.updateFromForm(form);
}
return ok("HI");
}
I have an alternative approach to this, where I add the annotation
#EntityConcurrencyMode(ConcurrencyMode.NONE)
to the Entity class.
This disables the optimistic locking concurrent modification check meaning the SQL becomes
update person set name=? where id=?
This is even more optimistic since it simply overwrites any intermediate changes.
Little bit late, but for your case #Version annotation should be the solution. We're using it mostly with java.util.Date, so it can be also used also for determining the date of last record update, in Play model that's just:
#Version
public java.util.Date version;
In such case update statement will be done with id and version fields only - useful especially when using with large models:
update person set name='Bob'
where id=1 and version='2014-03-03 22:07:35';
Note: you don't need/should update this field manually at each save, Ebean does it itself. version value changes ONLY when there was updated data (so using obj.update() where nothing changes doesn't update version field)
Mystery solved.
First- this public service announcement. "OptimisticLockException" is a big bucket. If you are trying to track one of these down be open to the idea that it could really be anything.
I figured out my problem by dumping SQL to the log and finding this:
update person set name='Bob'
where id=1 and email='jj#test.com'
and name='Robert' and password is null
and created=2013-12-01 and deleted is null
So I guess what happens when you do an update is that it builds a WHERE clause with all the known entities and their values as they were originally ready.
That means, if any other part of your code or another process changes something behind your back, this query will fail. I wrongly assumed that the problem was that somehow .setName('Bob') had changed the name in the DB or some object cache.
Really what was happening is that the WHERE clause includes a date while my database includes an entire timestamp with date, time, and timezone.
For now, I fixed it by just commenting out the timestamp in the model until I can figure out if/how Ebean can handle this data type.
I had the same problem,
after hours of search i found the reason..
It was of inconsistency of the parameters type in the data base (in my case string) and the object i created and tried to save -java.util.Date.
after changing the database to hold datetime object the problem was solved

Activiti BPM get Variables within Task

is it possible to get all process or task variables using TaskService:
processEngine.getTaskService.createTaskQuery().list();
I know there is an opportunity to get variables via
processEngine.getTaskService().getVariable()
or
processEngine.getRuntimeService().getVariable()
but every of operation above goes to database. If I have list of 100 tasks I'll make 100 queries to DB. I don't want to use this approach.
Is there any other way to get task or process related variables?
Unfortunately, there is no way to do that via the "official" query API! However, what you could do is writing a custom MyBatis query as described here:
https://app.camunda.com/confluence/display/foxUserGuide/Performance+Tuning+with+custom+Queries
(Note: Everything described in the article also works for bare Activiti, you do not need the fox engine for that!)
This way you could write a query which selects tasks along with the variables in one step. At my company we used this solution as we had the exact same performance problem.
A drawback of this solution is that custom queries need to be maintained. For instance, if you upgrade your Activiti version, you will need to ensure that your custom query still fits the database schema (e.g., via integration tests).
If it is not possible to use the API as elsvene says, you can query yourself the database. Activiti has several tables on the database.
You have act_ru_variable, were the currently running processes store the variables. For the already finished processess you have act_hi_procvariable. Probably you can find a detailed explanation on what is on each table in activiti userguide.
So you just need to make queries like
SELECT *
FROM act_ru_variable
WHERE *Something*
The following Test, sends a value object (Person) to a process which just adds a few tracking infos for demonstration.
I had the same problem, to get the value object after execution the service to do some validation in my test.
The following piece of code shows the execution and the gathering of the task varaible after the execution was finished.
#Test
public void justATest() {
Map<String, Object> inVariables = new HashMap<String, Object>();
Person person = new Person();
person.setName("Jens");
inVariables.put("person", person);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("event01", inVariables);
String processDefinitionId = processInstance.getProcessDefinitionId();
String id = processInstance.getId();
System.out.println("id " + id + " " + processDefinitionId);
List<HistoricVariableInstance> outVariables =
historyService.createHistoricVariableInstanceQuery().processInstanceId(id).list();
for (HistoricVariableInstance historicVariableInstance : outVariables) {
String variableName = historicVariableInstance.getVariableName();
System.out.println(variableName);
Person person1 = (Person) historicVariableInstance.getValue();
System.out.println(person1.toString());
}
}

Categories