Play framework merge POST with model - java

I am trying to learn the Play framework however i hit a roadblock and the documentation did not cover my issue (google resulted in nothing). What i am trying to do is making a multi page form that updates every time to the database.
Lets say the form is made in 5 steps and they cant be on the same page. What i've got working is that the first page works like intended (this also has the required data, the rest is optional)
ERROR executing DML bindLog[] error[Invalid value "null" for parameter "SQL"
After some searching i found that this had to do with the fact that the second page does not have the required data and thus sets those values to null. Meaning when i want to save the object it cant because all the other values are null.
Now my current saving code is pretty straightforward:
User userUpdate = Form.form(User.class).bindFromRequest().get();
userUpdate.update(id);
(the id value is from the action)
i've also tried the following:
User userUpdate = Form.form(User.class).fill(User.find.byId(id)).bindFromRequest().get();
userUpdate.update(id);
And in both cases my program crashes because of the null values.
So what i need is a push in the right direction to merge the current model with the form data so that i can save it. If someone has an good example on how to do it that would be really helpful!
P.s. this is my current model:
#Entity
public class User extends Model{
#Id
public Long id;
public String username;
public String firstname;
public String lastname;
public static Finder<Long,User> find = new Finder<Long,User>(Long.class, User.class);
public Form getUserFormByID(Long id){
Form<User> userForm = Form.form(User.class);
if(id > 0){
userForm = userForm.fill(
this.find.byId(id)
);
}
return userForm;
}
}

Related

What's the proper way of generating a unique field using Spring Boot / JPA?

First of all, I'm not taking about the primary id of the record. I'm talking about an field that is used by users to identify the record that's automatically generated but changeable by the user, not sequential and not a UUID. For example, starting with an account entity:
#Entity
#Data
class Account {
#Id
#GeneratedValue
private int id;
#Column(unique=true)
#NotNull
private String slug;
#Column
private String name;
}
and then I simply create a record:
#Autowired
private AccountRepository accountRepository;
Account account = new Account();
account.setName("ACME");
accountRepository.saveAndFlush(account);
At that point, the slug should have been generated, either completely randomly, or by doing something based on the name. How should that be done?
I know without locking the whole table it's impossible to ensure that the insertion won't result in an exception due to the uniqueness constrain being violated. I'm actually OK blocking the whole table or even letting the exception happen (you need a lot of requests per second fora conflict to happen between the check for availability and the insert).
If you separate the slug from the Account table and put it in a (id, slug) table by itself, you can generate the slug first (retrying until you succeed) and then persist the Account with a link to the just generated slug id.
You can't achieve this in a #PrePersist method, so your service needs to create the slug whenever you're creating an new Account. However it does simplify things on the application side (e.g. you don't need to wonder which constraint was violated when persisting an Account).
Depending on your other code, you can also get around locking the Account table and even the Slug table if you go for the optimistic approach.
A pseudo-code example of a service method that creates a new account (providing new Slug() creates the random slug):
#Autowired SlugRepository slugRepository;
#Autowired AccountRepository accountRepository;
public void createAccount(Account a) {
Slug s = null;
while(s == null) {
try {
s = slugRepository.save(new Slug());
} catch(Exception e) {
}
}
a.setSlug(s);
accountRepository.save(a);
}
I can think of JPA callbacks to generate the slug. In your case #PrePersist could be useful.
That said, why you need to make sure the value is available with a select before inserting the record, so the window for a collision to occur is tiny? You do have unique constraint on the column, right?
Update
Personally I would prefer to address it like this:
Use JPA callback #PrePersist when generating the the slug. Use to random UUID or timestamp to minimise the possibility of collision. No checking for collision as chances are minimal.
When updating the Account for user generated slug, always check first using query for collision. This check will offcourse happen in service update method itself.
This way I can be DB agnostic and also don't have to use repository/service in entity or listener classes.
I will do something like a separate Bean, helper or service class like this.
public class SlugService {
public String generateSlug(String slug)
{
if (accountRepo.getBySlug(slug) != null){ //check if it is already
return slug
} else {
slug.append("-"); //whatever the syntax
generateSlug();
}
}
public String makeSlug()
{
String slug = split by " ", replace by "_"(accountObject.getName);
generateSlug(slug)
}
}
Call the makeSlug(); method.

Generating a query at runtime using Room Persistance

I want to run queries on my SQLite database that have been generated at runtime (instead of the standard compiletime queries in the #Dao). For example I might want to search a TEXT column in the SQLite db, to see if it contains all words in a list of N length. In raw SQLITE, a query where N is 3 would look like this :
SELECT * FROM table
WHERE textValue LIKE %queryTerm1%
AND textValue LIKE %queryTerm2%"
AND textValue LIKE %queryTerm3%"
I have tried generating, and passing the end of the query, instead of just passing variables. For example :
String generatedQuery = "textValue LIKE %queryTerm1% AND textValue LIKE %queryTerm2% AND textValue LIKE %queryTerm3%";
tableDao.find(generatedQuery);
and in the #Dao:
#Query("SELECT * FROM tableName WHERE :endQuery")
List<POJO> find(String endQuery);
This doesn't seem to work for me. Do you have any idea how to get runtime generated queries working with Room?
PS:
I have debugged the Dao implementation and looked at the statement it is running. This confirms that the generated query information, and the query are being passed correctly. I assume this is an issue with SQL injection prevention (aka more of an SQLITE problem, than a Room problem)
Update: latest release 1.1.1 of Room now uses SupportSQLiteQuery instead of String.
A query with typed bindings. It is better to use this API instead of
rawQuery(String, String[]) because it allows binding type safe
parameters.
New Answer:
#Dao
interface RawDao {
#RawQuery(observedEntities = User.class)
LiveData<List<User>> getUsers(SupportSQLiteQuery query);
}
Usage:
LiveData<List<User>> liveUsers = rawDao.getUsers( new
SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
Update your gradle to 1.1.1 (or whatever the current version is)
implementation 'android.arch.persistence.room:runtime:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
The problem is you want to pass a part of SQL statement, but Room treats it like a query parameter.
If you want you can try to use Kripton Persistence Library, an open source library written (by me :) ) that drastically simplify SQLite's management code for Android platform and support situations like this.
Kripton works with DAO pattern too, so concept are quite similar. Just to write an example that fit your needs:
Given a model class:
#BindType
public class User {
public long id;
public String name;
public String username;
public String email;
public Address address;
public String phone;
public String website;
public Company company;
}
a DAO definition:
#BindDao(User.class)
public interface UserDao {
#BindSqlInsert
void insert(User bean);
#BindSqlSelect
List<User> selectDynamic(#BindSqlDynamicWhere String where, #BindSqlDynamicWhereParams String[] args);
}
and a data source definition:
#BindDataSource(daoSet={UserDao.class}, fileName = "kripton.quickstart.db", generateAsyncTask = true)
public interface QuickStartDataSource {
}
Kripton will generate at compile time all code is need to work with database. So to accomplish your task with Kripton you have to write a code similar to:
BindQuickStartDataSource ds = BindQuickStartDataSource.instance();
// execute operation in a transaction
ds.execute(new BindQuickStartDataSource.SimpleTransaction() {
#Override
public boolean onExecute(BindQuickStartDaoFactory daoFactory) throws Throwable
{
UserDaoImpl dao = daoFactory.getUserDao();
String[] p={"hello"};
dao.selectDynamic("name=?",p);
return true;
}
});
In logcat when code above is executed you will see the generated log:
database OPEN READ_AND_WRITE_OPENED (connections: 1)
UserDaoImpl, selectDynamic (line 352): SELECT id, name, username, email, address, phone, website, company FROM user WHERE name=?
selectDynamic (line 357): ==> param0: 'hello'
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)
Kripton obviously supports static where conditions too and many other features (i start to develop it in 2015).
For more information about Kripton Persistence Library:
https://github.com/xcesco/kripton
http://abubusoft.com/
https://github.com/xcesco/kripton/wiki

updating certain fields to prevent overwriting

I'm developing a Android-application using StackMob. Now I'm at the point that I want to save an object but not all his properties let's take this example.
class A extends StackMobModel
{
String UserOneInput;
String UserTwoInput;
}
Now I have two people using one instance of class A at the same time. User one puts his information in UserOneInput and user two in UserTwoInput. Now if user one saves hits information while user two already has fetched this object the situation would be
class A extends StackMobModel
{
String UserOneInput = "User one his input";
String UserTwoInput = null;
}
For user one while user two has
class A extends StackMobModel
{
String UserOneInput = null;
String UserTwoInput = null;
}
Now if player two saves his data it's saved as it is in his situation so we get
class A extends StackMobModel
{
String UserOneInput = null;
String UserTwoInput = "User two input";
}
User one his input is overwritten. I can fetch the object again before saving but if you use it on mobile networks the latency can still cause the same problem. (User two saves his information between the time that use one does a fetch and save)
I looked into the javadoc and only found a function that you can use to select certain fields but it says that won't work for saving.
Is there such an method for saving only certain fields of a class? Or is there some different model I should use to prevent overwriting?
The class does not know who is the owner, in order to know which one String to save.
This class must be decomposed to
class Answer {
String answer;
....
}
and
class Question {
Answer userOne;
Answer userTwo;
....
}
Each user has access to and saves his own Answer and the Question knows the Answers of the users.

Inputs in Play! for date and time?

I need to have 2 inputs in my form, one for date and one for time. In my model it is just one property of type java.util.Date. What is the best practice to handle generating the html and binding the input fields to the date property in the model using Play framework 2?
Note, if I use field constructors, I can't lay out the form the way I need to. I want a label on the first line, the 2 inputs on the second line, and validation errors on the third line. Should I just use raw html instead? If I do, will I still have access to validation errors and constraints?
It'd be certainly easier to bind if you were using two separate fields in your model. One idea would be to create an intermediate class which binds to the form submission.
// Controller
public static class FormSubmission {
public Date date;
public Date time;
}
public static Result submitForm() {
Form<FormSubmission> filledForm = form(FormSubmission.class).bindFromRequest();
if (filledForm.hasErrors()) {
return badRequest();
} else {
ModelClass model = new ModelClass(); // fetch first if you update
// Copy all values from form submission to the model
model.dateAndTime = combineDateAndTime(filledForm.get().date, filledForm.get().time);
}
return ok();
}
// View
#(form: Form[FormSubmission])
...
(I know this doesn't help, but tasks like this are extremely trivial in Scala.)

Need to know if each field has changed, how should I model this in Hibernate

So I have a class with three fields that maps to a table using hibernate
Class Widget
{
String field1;
String field2;
String field3;
}
On application startup a number of instances these widgets will be added to the database from an external files, but when I exit the application I need to know which (if any) of these fields have been changed by the user since the application was started, so the changes can be saved back to the files. I also need to store the original value for logging purposes.
I can't work whether I need a status field in the table or whether there is already a way of doing this using Hibernate/Database.
EDIT:A good solution to the program was given below . however the main reason I am using Hibernate is to reduce memory consumption so storing the original values when changed is not a good solution for me , I want everthing stored in the database. So I have create this new question How do I store a copy of each entity I add to database in Hibernate
Given an entity like the following you can track changes on one of it's field (while preserving its original value too).
#Entity
#Table(schema = "test", name = "test")
public final class Test {
private static final int ORIGINAL = 0;
private static final int CURRENT = 1;
private Integer id;
// holds the original and current state of the field
private final AtomicReferenceArray<String> field = new AtomicReferenceArray<>(2);
#Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Transient
public String getOriginalField() {
return field.get(ORIGINAL);
}
#Basic
public String getField() {
return field.get(CURRENT);
}
public void setField(String field) {
this.field.compareAndSet(ORIGINAL, null, field);
this.field.set(CURRENT, field);
}
#PreUpdate
public void preUpdate() {
System.out.format("Original: %s, New: %s\n", getOriginalField(), getField());
}
...
}
If there is a single row in a database like this:
id: 1
field: a
version: 2011-12-02 11:24:00
before the field gets updated (say, from a to b) you'll get the following output.
Original: d, New: b
The original value gets preserved even if the the entity is updated multiple times and both state can be accessed through the corresponding getters (getField and getOriginalField—you can get more creative than me in the naming :).
This way, you can spare yourself from creating version columns in your database and also can hide the implementation details from clients.
Instead of an AtomicReferenceArray you could use arrays, lists, etc, to track all changes like this way.
The #PreUpdate isn't necessary of course, but this way you can be notified of changes in the entity's state and atomically save the updated fields into file. There more annotations like these: see the documentation for javax.persistence for other annotation types.
If you are using MySql then you can get table's last update time from information_schema database like
SELECT UPDATE_TIME FROM `information_schema`.`tables`
WHERE TABLE_SCHEMA = 'dbName' AND TABLE_NAME = 'tableName'
Or else simple solution will be to add a column for update time stamp. By this you can even monitor which particular row has been updated.
If you need to synchronize with files as soon as you save into database, You can use the Hibernate event mechanism to intercept any save to database and save it to file, here's a sample doing that.

Categories

Resources