how to generate tables from enums with values in spring boot? - java

#Entity
public class User{
#Id()
private int id;
private UserStatus userStatus;
}
public enum Country{
Active, Pending, Blocked;
}
I want to create a UserStatus Table with the values inside.
1st approach would be to use #Enumerated with String or Integer.but, i dont want that, since these enum values can be changed.
Another approach is to have declare #Entity on the UserStatus class. add Id and value. Keep a ManyToOne mapping . so that, user will have the referenced foreign key as the userstatus.
Is it the best approach, if we want to persist the enum values in the table or is there any other approach ?
Can we generate the Gender table with enum values in it in spring boot?
[ The UserStatus enum is just an example. The main idea is to know what are the best approaches to create the table and it's value.]
I would be very glad to have some points around this.

Let's assume you are using MySQL as Database.
Now if I ask you
How will you store Country column in User table?
What will be Column type?
VARCHAR I guess.
Same approach is followed in #Entity level as well.
So this approachs sounds good to me
#Enumerated(EnumType.STRING)
private UserStatus gender;
Can read this post for more detail
Regarding your suggestion on
#Entity on the UserStatus
You are adding 1 more layer of complexity.
Will have to manage another Table. LAZY_LODAING, CASCADING and other stuff need to be handled.

Related

Is there a way of using a lookup table as a converter in JPA?

Imagine that I have a simple entity as follows:
#Entity
#Table(name = "PERSON")
public class Person {
#Id
#Column(name = "NAME")
private String name;
#Column(name = "GENDER")
private String gender;
}
And two tables, the actual table holding the information and a lookup table.
TABLE PERSON (
NAME VARCHAR2 NOT NULL,
GENDER INT NOT NULL);
TABLE GENDER_LOOKUP (
GENDER_ID INT NOT NULL,
GENDER_NAME VARCHAR2 NOTNULL);
I want to save the information from my entity into the table, so that the String field gender is automatically converted to the corresponding gender int, using the lookup table as a reference. I thought of two approaches, but I was wondering if there was a more efficient way.
Create an enum and use ordinal enum to persist. I would rather avoid this because I'd like to have only one "source of truth" for the information and for various business reasons, it has to be a lookup table.
Use the #Converter annotation and write a custom converter. I think that this would require me to query the table to pull out the relevant row, so it would mean that I would have to make a JPA call to the database every time something was converted.
I'm currently planning to use 2, but I was wondering if there was any way to do it within the database itself, since I assume using JPA to do all of these operations has a higher cost than if I did everything in the database. Essentially attempt to persist a String gender, and then the database would look at the lookup table and translate it to the correct Id and save it.
I'm specifically using openJpa but hopefully this isn't implementation specific.
Since you seriously considered using enum, it means that GENDER_LOOKUP is static, i.e. the content doesn't change while the program is running.
Because of that, you should use option 2, but have the converter cache/load all the records from GENDER_LOOKUP on the first lookup. That way, you still only have one "source of truth", without the cost of hitting the database on every lookup.
If you need to add a new gender1, you'll just have to restart the app to refresh the cache.
1) These days, who know what new genders will be needed.

How to restrict a user to enter only particular values in a jpa column?

I would like to restrict a user from entering values other than the given set of values into a jpa column.
For example, if I have a table like this..
sno sname college_name
----------------------
101 smith Stanford
102 jack Harvard
103 tiger Stanford
104 scott Harvard
and the class..
#Entity
#Table(name="student")
public class Student
{
#Id
#GeneratedValue
private Integer sno;
#Column(name="SNAME", nullable=false)
private String sname;
#Column(name="COLLEGE_NAME", nullable=false)
private String collegeName;
// setters and getters omitted
}
Is there a way, probably using annotations, to restrict the user to enter either Stanford or Harvard (case sensitive) into the college name.
Note: Instead of writing a trigger on the database side, I would want to achieve this via the Java program to save a database call. The above entity is container managed and that sno,sname,college_name are persistence fields, not properties.
Do I have to definitely perform a check before inserting? I am looking for another way?
Thanks in advance. Hope you will reply as soon as possible.
Rather than be a String you can change the type of collegeName to be an Enum.
Use Enumerated
http://tomee.apache.org/examples-trunk/jpa-enumerated/README.html
Btw, I wouldn't store the String values ("Harvard", "Stanford") directly in the DB table. Instead I would use codes (1, 2) and introduce a dictionary table with:
Code ¦ Value
1 Harvard
2 Stanford
Enums are a nice way to do it, but you probably can not foresee all universities in the world, so you might also consider using a different table with the known universities, and a many-to-one relation to it.
Ensuring that data is valid should usually be done with bean validation.
Database triggers or constraints are useful, but are not unique between different database providers.
Regards from Germany,
Thomas

Does it make sense to create entity table with only ID attribute?

Does it make sense to create a single entity when it should only contain the #Id value as a String?
#Entity
class CountryCode {
#Id
String letterCode; //GBR, FRA, etc
}
#Entity
class Payment {
CountryCode code;
// or directly without further table: String countryCode;
}
Or would you just use the letterCode as the stringvalue instead of creating the CountryCode entity?
It should later be possible for example to fetch all payments that contain a specific countrycode. This might be possible with both solutions. But which is the better one (why)?
Yes you can if you are using the entity as a lookup. In your example, you may want to add a column for description congaing (France, Great Britain, etc.) for the letter code and a third column whether it is active or not and maybe columns for when inserted and when it was last changed.
It makes sense to create such table to provide consistency of data, that is that no Payment is created with non-existing CountryCode. Having a separate entity (that is table) together with foreign key on Payment allows checking for consistency in database.
Another possible approach is to have check constraint on the code field but this is error prone if codes are added/deleted and/or there are more than one column of this type.
Adding the letterCode the the Payment Class as String Attribute (Or Enum to prevent typo errors) will increase the fetch performance as you do not need to create a join over your CountryCode Table.

Many to Many Mapping in Hibernate without Collection

Given a classic example of Student and Subject
where they have a many-to-many relationship,
is there any way to map them using POJOs w/o the use of Collections?
e.g.
Student.java
#Entity
class Student{
#id
int id;
String name;
}
Subject.java
#Entity
class Subject{
#id
int id;
String desc;
}
Tables
student (id,name)
subject (id,desc)
student_subject (student_id, subject_id) /* both foreign keys */
How will you query all subjects of a student?
Is it possible to generate these tables with the given beans?
Thanks in advance!
UPDATE: (I'll just give a background why I ask this ?)
My reason for avoiding Collections is that I would like my Service Layer to return data that is not tied to the Persistence Layer. Returning a Student object that has a list of Subjects will make my Service Layer Clients assume that they can get the subjects from the returned student object (then they'll get a LazyLoadException). If I make it EAGER loading, it would be overkill, since in many situations the client would only like the info about the Student and not get all his subjects.
To get all subjects, you need to join the tables like so:
select *
from subject
join student_subject
on subject.id = student_subject.subject_id
where
student_subject.student_id = ?
Is it possible to generate these tables with the given beans?
If you use the many-to-many mapping from Hibernate, it will create the query for you if you add the collections in the POJOs. Without the collection, you have to do it manually.
Note that the collections won't take memory unless:
You use them for the first time
Or you mark them a "load eagerly" in the POJO.
The default is lazy loading, so even if the tables are huge, you won't notice.
The question you should ask is, can you model your classes such that a many-to-many relationship can be established between them without collections?
It would be ideal to use collections and then let Hibernate use lazy-loading to populate the object graph.

JPA relationship

I have created two tables as person and address using JPA. I want to give one-to-many relationship between these tables. If I give the following
#OneToMany(mappedBy="address",targetEntity=person.class,fetch=FetchType.EAGER)
in the address table means it's not working correctly. Can any one help me?
Thanks in advance.
Without knowing anything about your architecture I will guess as to what you need.
JPA is smart enough to know how to join your tables so if you have id's in both tables you actually don't need to have "mappedBy" and "targetEntity".
You simply need to annotate your class as follows: (assuming your relationship is one address has many people).
Within the Address class:
#OneToMany
#JoinColumn(name="address_id")
public List<Person> getPeople()
{
return people;
}
This will place address_id as a field in your person table representing their associated address. Since you are declaring your list of type Person JPA will know to map to the person table (as long as the Person class is annotated properly with #Entity).
this is an example
#ElementCollection
#CollectionTable(name = "NUMBER")
private List<String> number;

Categories

Resources