Hibernate Mapping One-to-many in one table - java

We have the following (poorly designed?) table:
inputs:
keyword_id serial not null,
group_name string not null,
banned_term string not null
Keyword ID is the primary key. there are many banned terms per group_name. The data looks like this:
keyword_id | group_name | banned_term
1 | incentivization | free money
2 | inaccuracy | we're number one
3 | incentivization | win a free ipod!
There's no join table, and group_name isn't its own entity. I'd like a domain object something like this:
class BannedTermGroup {
Integer id;
String group_name;
Set<String> banned_terms;
// ... various getters and setters
}
The only examples on this one-to-many relationship between the group name and banned terms all involve some sort of join column or join table, while group_name would always be part of some other entity. Here neither is the case. Can this be mapped using Hibernate?

As quoted in my previous comment, you can get the ID of the group from nowhere.
Just to put aside this problem, you may look into Hibernate's reference, search for collections of basic types. It is what you need.
However, you still need to have a table for the "group".
assume it is as simple as a one column table:
KEYWORD_GROUP
--------------------
GROUP_NAME STRING
Your original keyword table:
KEYWORD
--------------------
GROUP_NAME STRING
KEYWORD STRING
I believe this is what you need:
#Entity
#Table("KEYWORD_GROUP")
public class KeywordGroup {
[.....]
#ElementCollection
#CollectionTable(name="KEYWORD", joinColumns=#JoinColumn(name="GROUP_NAME"))
#Column(name="KEYWORD")
private List<String> keywords;
}
For the keyword_group table, you probably don't need to create a new table if you are just using this model for read. Create a view from your original keyword table should be good enough.

Related

2 table in 2 many-to-many

I have 2 table:
Movie
movie_id
Stuff
staff_id
staff_name
crew_role_id
where crew_role_id - FK with static data(ex. director, actor etc.)
Also I have table movie_crew, which is just many-to-many table:
staff_id
movie_id
But in case the staff is an actor, I need add additional information who he plays(character_name) and what role he has(character_type)
So, we have another many-to-many table movie_cast like this
staff_id
movie_id
character_name
character_type
But it looks bad and hard to implement(don't repeat code).
The best solution I have is to add id to movie_crew, movie_crew_id, and then add this id to movie_cast. But I'm afraid that due to many unique id in movie_crew, we will have poor performance and so on. Are there better solutions?
I use MySql, Java(Hibernate)

Building a list with some hierarchical elements

I have a SQL table describing books in the online library. it looks like this:
create table if not exists BOOKS (
BOOK_ID char(36) default (UUID()) not null,
TITLE varchar(255) not null,
URL varchar(512),
PUBLISHED_ON date,
ISBN varchar(24),
ANNOTATION text,
COMMENTARY text,
RATING tinyint,
SERIES_ID char(36),
SERIES_VOL_NUM tinyint,
constraint BOOK_PK primary key (BOOK_ID),
constraint FK_BOOKS_SERIES foreign key (SERIES_ID) references BOOKS (BOOK_ID)
);
Foreign key to itself needed as books might be linked to a series (like Harry Potter has 7 books and James Bond series has over 40). The hierarchy might be 2, 3 and very rare cases 4 level deep.
I have created Java class Book reflecting the information in the table and another class
public class Series extends Book {
#JsonInclude(JsonInclude.Include.NON_NULL)
private List<Book> volumes;
// setters and getters omitted
}
When I am retrieving book info per given criteria, I am getting a plain list of all books and now I do need to build a list that will contain some hierarchy. I.e. I need to present it like following:
Book1
Book2
Series1
Volume 1 of S1
Volume 2 of S1
Part 1 of V2S1
Part 2 of V2S1
Volume 3 of S1
Book3
Book4
Series2
Volume1 of S2
Volume2 of S2
etc.
It is not a tree ( in that case I'd use recursion) and I am wrecking my brain on how to do it effectively. If someone can give me a hint, I will appreciate it.

JPA/Hibernate - Use unique constraint as primary key

I have the following problem, I have a already existing table with three fields field1, field2, field3. Field1 is actually a foreign key (#OneToOne) to another table. All field2 and field3 can be null, so I can't set a primary key for all three fields. In the database there is a UniqueConstraint for field1+field2+field3.
field1 | field2 | field 3
1 | 1 | null
1 | null | 2
3 | 1 | null
I've tried several solutions with JPA/Hibernate but could not find a good one.
Without defining a #Id JPA can not work (of course). Defining the three fields in a #Embeddable and reuse it with #EmbeddedId creates a primary key over all three fields which do not allow null values.
Is there any other solution than change the existing table and add a auto generated id for each row?
Thank you so much & best regards!
Have you tried as below?
#Table(
name="xxx",
uniqueConstraints=
#UniqueConstraint(name="my_unique_key", columnNames={"field1", "field2", "field3"})
)

Write efficient java code and oracle query

Design a system java same as relational database.
For example,
You Have employee table as below:
ID | Name | Manager | Salary
Now you can execute queries like :
select * from Employee where ID= ' something'
select * from Employee where Name= ' something'
select * from Employee where Name= ' something'
In same way you have a class Employee as bellow:
class Employee{
String ID;
String Name;
String Salary;
String Manager;
}
Now I want to query on this class as same as the SQL queries above,
How can I do it efficiently?
The code should be optimized on time complexity and space complexity.
In Java you have collections like List or Set which could be thought of as a Table or Rows.
You also have Map which acts like an unique index, and NavigableMap which works like a unique sorted index. There is also MultiMap which is like a non-unique index.

How Session.get method works in hibernate

I am trying to understand that how object initialization works for returned object by Session Get method.Please validate my understanding. When it executes, it checks for object with given identifier in the first level cache and then the Second level cache (If it is configured), If not found then fires the select query to retrieve the data from database.
My question is, Does it include associations in select query which are configured for lazy loading or null value is set for such associations in returned object?
If this is case then session.get does not do the complete initialization of the returned object which is contradictory to what is written on most of hibernate tutorials available on web.
Hibernate Session provide different methods to fetch data from database. Two of them are – get() and load().
get() returns the object by fetching it from database or from hibernate cache.
when we use get() to retrieve data that doesn’t exists, it returns null, because it try to load the data as soon as it’s called.
We should use get() when we want to make sure data exists in the database.
For Example :
In a Stock application , Stock and StockTransactions should have a “one-to-many” relationship, when you want to save a stock transaction, it’s common to declared something like below.
Stock stock = (Stock)session.get(Stock.class, new Integer(2));
StockTransaction stockTransactions = new StockTransaction();
//set stockTransactions detail
stockTransactions.setStock(stock);
session.save(stockTransactions);
Output :
Hibernate:
select ... from mkyong.stock stock0_
where stock0_.STOCK_ID=?
Hibernate:
insert into mkyong.stock_transaction (...)
values (?, ?, ?, ?, ?, ?)
In session.get(), Hibernate will hit the database to retrieve the Stock object and put it as a reference to StockTransaction.
To answer the question:
Does it include associations in select query which are configured for lazy loading or null value is set for such associations in returned object?
1) The session.get() will NOT initiate lazy stuff. NEVER. In fact that is the central thought of the design. Otherwise - we would be able to load whole DB in one SHOT (in one JAVA call to session.get())
2) And also there WILL NOT be null instead. Each reference or collection will be represented by proxy. This is the way how we can avoid to load compelte DB in one shot (all stuff initialized with one method get). Because each proxy is in fact a promise - once we will touch it... it will load the real data.
And so on. So get is very safe way how to recieve as few data as was configured....
Simply
When get() method is called, it will directly hit the database, fetch the result and return. If no matching fields are found, it will gladly return null.
Depending on the annotations on references, Lazy or Eager, data will be returned. if Lazy, proxy will be returned instead of null, if Eager, fully initialized object will be returned.
Better to monitor the queries at the backend, for good understanding.
1) Customer entity class that map the T_CUSTOMER DB table:
#Entity
#Table(name= “T_CUSTOMER”)
public class Customer {
#Id
#Column (name=“cust_id”)
private Long id;
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn (name=“cid”)
private Set<Address> addresses;
…
…
…
}
2) Address entity class that map the T_ADDRESS DB table:
#Entity
#Table(name= “T_ADDRESS”)
public class Address {
// Fields and Properties
}
Consider this Customers table :
----------------------------------------------------------------------------
| Cust_id | Cust_firstname | Cust_lastname | Cust_email | Cust_mobile |
----------------------------------------------------------------------------
| 101 | XXXX | YYYYY |xxx#xyz.com | 8282263131 |
----------------------------------------------------------------------------
The Above customers table is having one record with cust_id as 101.
Now Consider this Address Table :
----------------------------------------------------------------------------
| id | street | suburb | city | zipcode | cid |
----------------------------------------------------------------------------
| 1 | streetX | AreaY | cityZ | 54726 | 101 |
----------------------------------------------------------------------------
| 2 | streetXA | AreaYB | cityZS | 60660 | 101 |
----------------------------------------------------------------------------
Now When you invoke :
Customer cust = (Customer)session.get(Customer.class, 101);
Then Hibernate will fire a SQL Query Something like :
1). In case of EAGER LOADING :
SELECT * FROM T_CUSTOMER cust JOIN T_ADDRESS add ON cust.cust_id=add.cid
i.e, It will load all the data related to the T_CUSTOMERS table and it's associated tables, which is T_ADDRESS table in this case.
2). I case of LAZY LOADING :
SELECT * FROM T_CUSTOMER WHERE cust_id=101;
So, it only fetches the data corresponding to the T_CUSTOMER table and uses Proxy for the T_ADDRESS table as said above by #Radim Köhler. It will fetch the data from the T_ADDRESS TABLE only when you'll call :
cust.getAddresses();

Categories