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
Related
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.
I am trying to create Student and Address objects from a table called STUDENT_ADDRESS that is defined as below.
Table Name: STUDENT_ADDRESS
Columns:
STUDENT_ID
STUDENT_NAME
STUDENT_END_DATE
STUDENT_ADDRESS_END_DATE
ADDRESS_ID
ADDRESS_VALUE
ADDRESS_END_DATE
I am aware that this is the most inefficient table that can ever be created. But changing the table structure is an uphill battle that I will most likely lose.
What I am trying to do is to create a Student object that has a set of Address objects, and the address objects can be filtered out based on both the STUDENT_ADDRESS_END_DATE and ADDRESS_END_DATE.
I hope that made sense. Thanks in advance for your help. :)
You can look this up in Hibernate recipes under "disasters waiting to happen" :)
However if you really must then maybe try it with discriminators?
I'm not sure if this will do a one to many relationship though.
#Entity
#Table( name = "OBJECT")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
name="OBJ_TYPE",
discriminatorType=DiscriminatorType.STRING,
length=1
)
#DiscriminatorValue("c")
public class ObjOne {
...
}
#DiscriminatorValue("b")
public class ObjTwo {
....
}
Be vary wary of creating a n + 1 problem (see What is SELECT N+1?) when building a hierarchy within a single table, as this will ruin your day, which was probably going well after you got the initial issue sorted...
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
we havent used JPA or any other ORM tools in our web application, now we have been on updating whole stuff to Java EE 6,
my problem about is JPA
,i have been looking for an answer,and learn how people solve that kinda issue,
i have 2 entites,
#Entity Person
{
#Id
private long id;
#JoinColumn(name="CITY_ID")
#OneToOne(fetch=FetchType.LAZY)
private City city;
....
}
and my second entity
#Entity City
{
#Id
private long id;
private String name;
.....
}
i am querying person entity and i show one on my jsf page
i have 2 input fields for Person.city to show on my jsf page
inputhidden for id and inputtext for name
people are selecting cities from a popup then
i set hidden component for city id, with new selected new value,
and the same for name,
everthing goes fine till now,
when i merge Person Entity, it tries to merge City also, but with an id already defined on table, so constraint error for Cirty Id.
what are you doing for this kinda problem?
i thought valueChange action for inputHidden,but at jsf Life cycle it happens before update model so even if i replace Person.City entity with new one in action ,
it will updated again (actually with the same values but it will be done twice)
,So what is the best workaround for this situation?
thanx
You are trying to save a new Person and assign it to an existing City? If so, and if you are using PersistantManager.persist(person) than it tries to create a new City, which fails. You can tell the relationship from Person to City what options to follow, see Cascading (MERGE in your case i guess).
Seam Faces ,converter as it explains in here u need special id to entity converter,
that was my problem
I ran some DDL script to setup a complete country table in my database. The country table's primary key column contains the corresponding ISO code for every country.
In my JPA project I have a User entity having an embedded Address entity and this Address entity has a reference to a Country. The relationship between User and Address seems to be no problem to me, but the relationship between Address and Country. I tried to map it as a ManyToOne relationship, since many addresses can share a country.
Problem is: I annotated the iso member variable of the Country class with Id -> Now, JPA/Hibernate complains about not having set the id of the country manually. But in this case, the id is already given and set, since I imported the data once and the ISO code is unique and by db schema means declared as primary key. In this special case, there is no need for updates or inserts in the country table - the information should be read only!
Any idea what to do, so I can use my countries table without altering?
Your question is missing some details, so the following involves a lot of guessing :-)
Your Country class should look something like:
#Entity
#Immutable
#Table(name="countries")
public class Country {
#Id
private String isoCode;
// all other attributes, getters / setters, etc...
}
#Immutable is a Hibernate extension to JPA standard; you don't have to put it on entity but having it will result in slightly better performance. Keep in mind that it will really make the Country immutable - you won't be able to create / update / delete countries through your application. You may want to configure cache for your Country entity as well if it's used often enough.
Your Address would have the following mapping to country:
#ManyToOne
#JoinColumn(name="country_iso_code")
private Country country;
Note the absence of "cascade" attributes - you don't need any. The final important point here is you actually need to get or load the Country instance to set it on address:
Country country = (Country) session.load(Country.class, isoCode);
// OR
Country country = (Country) session.get(Country.class, isoCode);
address.setCountry(country);
...
session.saveOrUpdate(address);
The first line above will not hit the database; use it if you know that country with such an ISO code exists. Second form will hit the database (or cache, if configured) and return NULL if country with that code does not exist.