Relational Data is Not Storing in Ebean - java

Background
I am using the Play Framework(Java) to store data. Play Framework uses
Ebean to convert classes into data that can be stored in a database.
I am having issues creating One To Many database relationships. I am trying to create a relationship between a User model and a UserEmail model. Where each User may have many UserEmails.
User Model Code
User Email Model Code
The Issue
When I create a User and then add a UserEmail, it does not seam to save the UserEmail in the database. I have tried doing so many ways.
By adding to the List<UserEmail> emails and then saving the User(Code)
Result: New User is stored in database with correct info, However no new UserEmail is stored in the database
By creating a static create method in UserEmail(Code)
Result: No UserEmail was stored in the database
By adding to the List<UserEmail> emails and then saving the UserEmail and the User(Code)
Result: New User is stored in database with correct info, However no new UserEmail is stored in the database
Question
In Play Framework(Java), how do you create and store Relational Data? Is there some step I am missing? Do I have to add another Annotation to the models to make it work?
Update
After some further testing it looks like saving the User object with a new UserEmail will save it to the database. However when I fetch a user
User retrievedTestUser = User.find.where().eq("userId", testUserId).findUnique();
It does not retrieve the UserEmails

Add information about reverse field:
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
public List<UserEmail> emails;
Details in documentation

Above problem was because there was #Id annotation missing in UserEmail class.
Adding below code solves the problem:
#Id
public String email;

Related

Spring's Entity inside nodejs

The way I manage persistent state inside my backends in the past is by using Spring's #Entity. Basically, I define a regular java class like this:
#Entity
#Table(name = "users")
class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
public Long user_id;
#Column(name = "email")
public String email;
}
Then I can use Hibernate to retrieve a managed java object:
User user = userFactory.getUserFromId(3L); // uses Hibernate internally to get a managed instance
user.email = "abc#company.com"; // gets auto-save to mysql database
This is highly convenient, as I can just change the fields without explicitly worrying about saving data. It's also quite convenient as I can specify a number of fields to be used as an index, so I can search for matching email names quite fast.
How would I go about doing the same thing using NodeJS? I need to use node as my team is not familiar with Java at all. I want to be able to store complex json objects fast, have a cached version in memory that ideally stores data permanently at regular intervals.
My current plan is to use Redis for this. Getting user's object should look something like this:
class User {
constructor(json) {
this.json = json
}
async save() {
await redis.set(JSON.stringify(this.json));
}
}
async function user(id) {
let json = JSON.parse(await redis.get("user-" + id));
return User(json);
}
u3 = await user(3);
u3.json.email = "def#company.com";
u3.save();
To get user by name, I'd create my own index (mapping from email to user id), and potentially store this index inside redis as well.
All of this seems clunky, and feels like I'm reimplementing basic database features. So before I do it like this, are there different ways to manage json objects well in js, so that the coding experience is somewhat the same as in Spring?
What you need is an ORM, that is that tool in every language that maps your objects into database records.
With a quick search you can find Sequalize that is very popular in the NodeJS world.

Mapping single bean class to multiple tables in hibernate

I have developed a spring rest service which will accepts a json input and freeze the details in to database and return the status as json output. everything is working fine.
now i need to update the service with the new requirement, i will get address details of the user and i need to update the address table as well. My question is
1) How to change the input request currently my controller is as follows
#Requestmappping(value="/register", metod=RequestMethod.POST)
public #ResponseBody ResponseEntity userRegis(#RequestBody UserBean userdetails){
}
2) How to change the UserBean format. Currently it is mapping to one single table. Now i need to update the bean with address fields. and i need to map the address fields to new table.
please help on this.
What you are referring to in composition in OOP. So, basically user has address or addresses.
class User {
....
private Address addres;
//private List<Address> addres; use something like this if user has multiple addesses
}
class Address {
}
And offcourse you would not want to map same bean to multiple tables or something like that. The above relation is simple parent child relation. Read here

Relational Data is Not Fetching in Ebean

Background
I am using Play Framework(Java) to store data. Play Framework uses Ebean to convert classes into data that can be stored in a a database.
Issue
I am currently having trouble fetching relational data completely. I have a User and a UserEmail model. The User can own multiple UserEmails.
User Model Code
User Email Model Code
When I try and fetch a User, the User data is fetched correctly, however the UserEmails are not.
Fetching Code
When I specifically add fetch("emails") to the fetch code
User.find.fetch("emails").where().eq("userId", testUserId).findUnique();
It seams like it at least gets the emails. However when I try and show them via
return ok(Json.toJson(retrievedTestUser));
I get This Error
Question
Is there some way I can make Play Framework/Ebean automatically fetch the emails without adding fetch("emails") to every query? Maybe an annotation?
How do I resolve the error above? I get why it is thrown, but how can I fix it? Is there any way to have it only fetch one level deep?
I have found solution to above problem. Every entity should have id.
User class has field annotated with #Id but UserEmail has not.
After adding #Id annotation above email field of UserEmail class user is fetched properly and its email list is not empty.
#Id
public String email;
One more thing that I spotted in your code:
When you are creating bidirectional relation then you should use mappedBy attribute on one side to indicate that these are two ends of one relation and not two separate relations. So there should be:
#OneToMany(mappedBy="user", cascade = CascadeType.ALL)
#Constraints.Required
public List<UserEmail> emails;

Administrator being able to delete any user from the database

I have a simple small application which involves an admin having the ability to update and delete information or individual user's from a database. Basically, so far the administrator can view all the current registered user's in a table format on a page. I need to know how I can delete or update the user information based on the user in each row, so assuming based on their actual userID. So far I have been able to extract all the user's from the database and put them into a table, and using JSTL fill in the necessary table values(username, email, etc..).
I do not know, the proper process for doing this, and do not know how to code up the controller to handle this specific task. So far my controller is like this:
#RequestMapping("/deleteUser")
public String deleteUser(#RequestParam(value = "id", required= false) Integer id) {
usersService.delete(id);
return "users";
}
where the request mapping comes from a button in the table, and "return users;" just returns back to the same jsp page which displays all the users. This is a little buggy, and I would like to know what would be the proper and best way to implementing this functionality.
Check the users Authority with the Principal.
#RequestMapping("/deleteUser")
public String deleteUser(#RequestParam(value = "id", required= false, Principal princiapl) Integer id) {
// Check if user has admin authority using principal.getAuthorities();
}
You could also use the #Secured("ROLE_ADMIN") annotation and lock down the method to the admin role.

Expressing Audit functionality with JPA annotations

I'm in the middle of fumbling around with JPA. I've so far successfully created an entity representing the user data and a stateless bean for the access to the user data.
The data the users can work on is like this (SQLFiddle link):
CREATE TABLE data
(
email character varying(128) NOT NULL,
data character varying(128) NOT NULL,
lastchange timestamp NOT NULL,
CONSTRAINT email_data PRIMARY KEY (email,data)
);
The idea is to save the unaltered, current version for all users with an empty email key. Then, when a user alters the data and creates an auditable version, the email field is filled with the users email. This way, each user can alter their copy of the data. The merging is a problem for a later date and not part of my question.
Now, I have the entities already in place. I created a stateless bean to load/save/find the data records by using the EntityManager. The logic to load the user specific version first, then load the unaltered version if the user has no user specific version still eludes me.
Consider this part of the bean:
#Stateless
public class DataBean {
#PersistenceContext(unitName = "authPU")
private EntityManager em;
public List<DataEntry> findAll() {
TypedQuery<DataEntry> query = em.createQuery("SELECT d FROM data d", DataEntry.class);
List<DataEntry> list = query.getResultList();
return query.getResultList();
}
...
}
How do I inject the user information into this class? I need to get the data for the current user first, then get the data for all users if there's no user-specific data available.
You could use standard EJB authentication. Then you can call SessionContext.getCallerPrincipal() in your session bean to get a user ID. Use this user ID to query the database.
In this case you have to add another column to your table (containing the user ID), if the authentication user ID does not equal the email address.
Far simpler (but less elegant) is to add the email address to the arguments of your EJB service method: Just make it part of the public API.

Categories

Resources