A person's address may look as the following:
country: USA
state: Some state
city: N.Y.
Street: some stree name with buildings
Building: number of the building on the street
Or as an alternative if building consists of several apartments/rooms another entity should be used:
Apartments/rooms: number of the apartment in the building
every next level in the example has the parent one as a foreing key that cannot be null:
county - is a container of states
state - is a container of cities and so one.
building - may be or may be not a container of rooms/apartments.
As a result I have the following tables for each level:
country
id name
1 USA
state
id country_id name
2 1 N.Y.
city
id state_id name
3 2 New York
Street
id city_id name
4 3 Some Street Name
Building
id street_id number
5 4 28
apartment
id building_id number
8 5 36
The problem I've met is how to map person to this tables structure?
Person may or may not live in an apartment, if it's a big family house for instance.
Ideally I'd like to have a collection of some entities:
ManyToMany
Collection<SomeEntity> addresses ...
where SomeEntity can refer either to an apartment or to a building directly.
Here are options I'm considering now, but I don't like them.
The first option where SomeEntity will have a type - either building or apartment and it will look like:
SomeEntity
id person_id type address_id
10 11 building 21
11 13 apartment 24
where in the first case it address_id refers to the building table, in the second one - to the apartment table.
The second option is to have a table that have the following list of fields:
SomeEntity
id person_id country_id state_id city_id street_id building_id apartment_id
In this case, if a bulding has no rooms, the apartment_id field is null. Also it's useful if I need for example to get list of persons who live in the city/or on the street cause I don't need to join all address-related tables, just refer to SomeEntity table. What do you think about this table? How to map the Person object in this case? SomeEntity - is just a table, not the object. My services actually should not know anything about internal tables structure. This issue is not clear to me. Probably you can offer the better solution.
Please, help.
if something similar to my comment is your solution then what you asked is how to map join in hibernate.
it will be something like this :
#Entity
#Table(name = "TEST_TABLE_A")
public class TestTableA {
public TestTableA(){
}
public TestTableA(String aName){
this.aName = aName;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "A_ID")
private Long id;
#Column(name = "A_NAME")
private String aName;
//some other atribut here
#ManyToMany(cascade = CascadeType.REFRESH)
#JoinTable(name="A_JOIN_B",
joinColumns={#JoinColumn(name="A_ID")},
inverseJoinColumns={#JoinColumn(name="B_ID")})
private Set<TestTableB> testJoins = new HashSet<TestTableB>();
//Getters and setters of all the collumn here
}
you can assume the TEST_TABLE_A is your BUILDING table in your database, and TestTableB is your apartment entity. and A_JOIN_B is your SOME_ENTITY table, and testJoins is the object you are looking for. You must get that object from the Building through.
You may want to change the relationship to #OneToMany if you want. and change the Cascade.Type (detail about cascade) so it will be easier for you to maintain that table.
Related
I have a join table with an extra column for a many-to-many relation between Users and Projects. It looks like this:
user_id (pk)
project_id (pk)
role (pk)
1
1
MANAGER
2
1
WORKER
1
2
MANAGER
1
2
WORKER
In this example, project 1 has two participants, user 1 is there, with the role of a manager, user 2 is there with the role of a worker. In project 2, there is only one participant, user 1, which is in the role of a manager and a worker.
What I want to accomplish is a Java representation like this:
#Entity(...)
class ProjectRole {
// some annotations
private User user;
// some annotations
private Project project;
// some annotations
private Set<String> roles;
// getters and setters
}
I'm aware of two indirect ways to get such an object.
Alternative 1: Map an Entity of the table with:
#Id
#ManyToOne
#JoinColumn(name = "user_id")
User user;
#Id
#ManyToOne
#JoinColumn(name = "project_id")
Project project;
#Id
String role;
and combine multiple hits for the same user (per project) and map it to an object like the wanted structure above, but this would not allow to use sortings or pagination in the future and it would be nice to get the target structure directly.
Alternative 2: I could create an artifical Table participants with an artifical participant.id and use this in an participant_roles table. So I get two entities, while the first one can have a Set<ParticipantRole>. But I have to save a lot of unnecessary information in the database.
Maybe it is impossible, since an Entity-instance is more or less a representation of a row in the database, so I will always get multiple entries per user (per project). Or is there something I haven't seen so far to accomplish it?
Just use the option 1 and expose the details through some dedicated method that does the grouping on-demand or in a #PostLoad event listener. Hibernate/JPA needs the information to be bidirectional and the kind of mapping you want here is more or less a projection of the normalized data.
I am reading data from old legacy dabatase. Somehow, they place all non-existing relationship using 0 index, for example:
Object Person:
id: 123
name: john
surname: snow
birthCityId: 0 <-- this means that there is no relationship between city and this person.
Now, in JPA I have the problem that it is loading person entity but it cannot find related city entity with index 0. I would like to code that when I have city with ID 0, then City entity is set to null.
How can I do that?
I don't want to create a new entity with index 0 into the db.
Thanks
You can use the Hibernate #NotFound annotation:
#ManyToOne
#NotFound(action=NotFoundAction.IGNORE)
private City birthCity;
https://docs.jboss.org/hibernate/orm/5.3/javadocs/index.html?org/hibernate/annotations/NotFound.html
I do not see the other posted solutions working as an exception will occur on Hibernate load i.e. prior to you being able to handle it by other means.
I am asuming u have
Person{
#Many2One #JoinColumn("birthCityId") City birthCity;
...}
the easiest solution is to add table row with id=0 in city and the rest be nulls
and this to your class
#PostLoad
public viod cityInit(){
if(birthCity!=null&&birthCity.getId()==0){
birthCity==null;
}
}
There are more elegant solutions but this will get you started quickly
In my EclipseLink JPA system I want to access a custom query using a OneToMany. Unfortunately the database is not normalized.
Simplified my DB looks like this:
Company
ID Name
-----------
01 CompanyA
02 CompanyB
Person
ID Company_Id Name Occupation
------------------------------
01 01 Alice Management
02 01 Bob Accounting
03 01 Carl Accounting
The occupation is given as a natural key.
Very simplified I have the following code:
#Entity
class Company {
#Id
#Column private Integer id;
#Column private String name;
#OneToMany()
#JoinColumn(name="Company_Id")
private List<Person> persons;
}
#Entity
class Person {
#Id
#Column private Integer id;
#Column private Integer company_id;
#Column private String name;
#Column private String occupation;
}
So far it is running fine. Now I want to add a OneToMany relationship that that lists the occupations and gives me the possibility to get a list of persons that have that occupation.
I want to do:
for (Company c : myCollectionOfCompanyEntities) {
System.out.println(c.name);
for (OccupationsInCompany o : c.getOccupations()) {
System.out.println(o.name);
for (Person p : o.getPersons()) {
System.out.println(p.name);
}
}
}
How do I start to write that OccupationsInCompany class? If I simply create an entity class, JPA wants to read the data from a table.
I know how to get all the data by hand using custom queries. But is it possible to do this using OneToMany annotations?
You should be able to do this by using the #ElementCollection annotation.
#ElementCollection
#CollectionTable(name = "PEOPLE", joinColumns = {#JoinColumn(name="Company_Id")})
private List<Person> people;
Useful link at WikiBooks.
There are many ways to do this, but unless listing people by the occupation in a company is large part of the application, I don't know that it makes sense to add objects to your model that might affect any other use cases negatively - you will be forced to maintain this model when you may only want it sorted at one point in time.
Other options:
1) take your list of people and sort them by occupation in memory within the getOccupations method. This can then be stored in a transient occupation list so it doesn't need to be repeatedly done.
2)Query for it in one query. "Select c.name, p.occupation, p.name from company c join c.persons p order by c.name, p.occupation where..". This one query gives you everything without the need to traverse your object model. Depending on how often this is needed, you can add options to make either more efficient for your use cases.
Option 1 can be combined with JPA so that the organization list is populated upfront, such in a postLoad method. Any model changes will result in extra complexity and result in JPA doing the same work the model itself can handle just as well if not better.
How do I store integer type list in a comma-separated format in Hibernate?
For example - I have a city table where I have cityId and CityName. In another table I have employee details.An employee can be tagged with multiple city.
I have created another table for employee-city mapping where I want to store the cities in comma separated format.
Table- Employee
----------------------------
Employee_ID Employee_Name
1 Employee 1
2 Employee 2
Table -city
------------------------
City_ID City_Name
1 City_1
2 City_2
Table- Employee-City Mapping
-----------------------
Emp_ID City_id
1 1,2
2 1,2
How to do the this kind actions in Hibernate ? Please help. I am using MySQL as the database backend.
It looks like you are trying to represent a one-to-many relationship.
The conventional SQL way to represent a one-to-many relationship is via multiple rows in a join table. In your case the join table is the employee-city table with a modified design with multiple rows per city rather than multi-valued columns:
Table- Employee-City Mapping
-----------------------
Emp_ID City_id
1 1
1 2
2 1
2 2
JPA (which Hibernate supports) has direct support for mapping these relationships to Collection fields. Your Employee class would have a cities field with type List<City> annotated with #OneToMany.
#Entity
public class Employee {
#Id
#Column(name="Emp_ID")
private long id;
#OneToMany
#JoinColumn(name="Emp_ID", referencedColumnName="City_ID")
private List<City> cities;
// ... rest of the class: constructor, getters, setters
}
The following guide may also help:
https://en.wikibooks.org/wiki/Java_Persistence/OneToMany
I would like to write a JPA entity class that has a one to many relationship. I would like to avoid defining the relationship in the parent class to avoid the data to be loaded every time a reference is made for the object even when there is no need for the associated data. I have read that even with Lazy loading, the data can be loaded so i need to avoid that.
In the following example,
Customer table
------------------------
customerid, customerName
1 John
2 Bob
Order Table - customerId is a foreign key to Customer
orderId, customerId, orderDate
1 1 12MAY2012
1 1 13MAY2012
1 2 16MAY2012
JPA Entities
#Entity
public class Customer {
// all Customer-related fields WITHOUT #OneToMany relationship with Order
}
#Entity
public class Order {
String orderDate;
#ManyToOne
private Customer owner;
}
How would i retrieve data from the customer table based on a condition on the order table? For example, how can i say "Get me all customers who have made an order where the orderDate is between two dates?
using hbm.xml there are query only properties to achieve what you want
http://ayende.com/blog/4054/nhibernate-query-only-properties