Hibernate: mapping collection property with alternate join column - java

Scenario: Hibernate 3.6 with xml-based mapping, Java7, Postgresql 8.3.
I'm currently refactoring an application where I have got this scenario for the database:
main_table
id integer
other_field string
(id) PK
secondary_table
other_field string
value string
(other_field, value) PK
Basically, there's a secondary table which contains an "other_field" which is matched on the main table; I need to extract all values for a certain record in main_table and map them.
In SQL I'd use a query like:
SELECT value FROM secondary table INNER JOIN main_table ON secondary_table.other_field == main_table.other_field where main_table.id = 1;
But I don't understand how to map a collection of basic types (strings) to the Main object in Java using such a query (or a similar one if the one I propose is not hibernate friendly), so that I can have a "values" property on my mapped object, which should be a Set<String>

I think this is what you are looking for:
#Entity
public class Primary { // Main table
#Id
#Column(name="EMP_ID")
private long id;
...
#ElementCollection
#CollectionTable(
name="PRIMARY_SECONDARY",
joinColumns=#JoinColumn(name="PRIMARY_ID")
)
private Set<Secondary> phones;
...
}
#Embeddable
public class Secondary { // Secondary table
private String value;
...
}
Full example and further details.

Related

JPA: dynamically mapping an Entity to a table based on an instance variable

Here is the problem i have:
class CurrencyPrice {
#Transient
String pair;
float spotPrice;
Date timeStamp;
}
And I have 3 table the names of which stand for "usd value of euro/gbp/yen respectively": usd_euro, usd_gbp & usd_yen. They all have the same 3 columns: id, spotprice, timestamp.
For some reason i cannot have a single table. The transient instance variable 'pair' will have the following values depending on what it represents: "usd_euro", "usd_gbp" & "usd_yen"
And depending on the value in 'pair' I want to insert a row in one of the tables, eg: if I have the value "usd_yen" in 'pair' then the object should be persisted in usd_yen table.
And when I want to fetch data, I want JPA to decide which table to SELECT from based on the value in 'pair'
This is simple in JDBC but is there a way to do this in JPA?
Thank you.
If I understand your requirements correctly, this might actually be feasible in JPA now (those threads you cite are quite old), if you can use inheritance on your entity and an additional join table and if it's acceptable that the ID for each type is not contiguous.
You could basically define your classes like this then:
#Entity
#Table(name="curr_base") // choose a suitable name
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="currency", discriminatorType=DiscriminatorType.STRING) // your join table needs this column in addition to the id
public abstract class CurrencyPrice {
#Id
private int id;
}
#Entity
#Table(name="usd_euro")
#DiscriminatorValue("usd_euro")
public class UsdEuroPrice extends CurrencyPrice {
float spotPrice;
Date timeStamp;
}
#Entity
#Table(name="usd_gbp")
#DiscriminatorValue("usd_euro")
public class UsdGbpPrice extends CurrencyPrice {
float spotPrice;
Date timeStamp;
}
#Entity
#Table(name="usd_yen")
#DiscriminatorValue("usd_euro")
public class UsdYenPrice extends CurrencyPrice {
float spotPrice;
Date timeStamp;
}
I replicated spotPrice and timeStamp on each subclass so that you don't have to modify your existing table definitions - of course it would be much cleaner to only have them on the superclass/join table.
This mapping allows it for example to perform a EntityManager.persist(new UsdGbpPrice(...)) and have JPA insert a row into the right table. For more information, look here.

JPA/Hibernate mapping with #SecondaryTable annotation

I have two tables:
part {
int id; --> primary key, auto generated
varchar poNo;
varchar partNo;
varchar partDesc;
varchar eccNo;
...
}
supplement {
int id; --> primary key
varchar poNo; --> foreign key
varchar partNo; --> foreign key
varchar venderPartNo;
varchar exportHSCCode;
...
}
I defined one Entity as below:
#Entity
#Table(name="part")
#SecondaryTable(name="supplement", pkJoinColumns ={#PrimaryKeyJoinColumn="id"})
public class Part{
#Id
#GeneratedValue
private Integer id;
private String poNo;
private String partNo;
private String partDesc;
private String eccNo;
#Column(table="supplement")
private String vernderPartNo;
#Column(table="supplement")
private String exportHSCCode;
...
getter and setter...
}
Question 1:
when I persist one part, I dob't want to insert one row into supplement table, is there has any configuration or annotation can get it? Because according to above Entity and configuration , when I persist one part, hibernate will generate two insert SQL statement for me:
insert into part(poNo, partNo, partDesc, eccNo) values (?,?,?,?)
insert into supplement(vernderPartNo, exportHSCCode, id) vaules (?,?,?)
which I want is, when persist one part, I didn't set value for any filed of supplement, then just one insert statement:
insert into part(poNo, partNo, partDesc, eccNo) values (?,?,?,?)
is it possible?
Question 2:
from the table schema of above, the poNO and partNo is the foreign key, that means , for every related part and supplement, this two field should be has the same value. But I don't know how to map this two column value to supplement table when using the configuration as above.
As for the normal operation for Hibernate, when it process one part, it always generate two insert statement which I mentioned above, and for the secondary table, it's insert statement just contains those fields which has specified it's table name, so for supplement, it's insert statement is :
insert into supplement(vernderPartNo, exportHSCCode, id) vaules (?,?,?)
So, is there has any way to let Hibernate generate the insert statement as below:
insert into supplement(poNo, partNo, vernderPartNo, exportHSCCode, id) vaules (?,?,?,?,?)
to map two tables with #SecondaryTable
you can use like below on the primary table
#Table(name = "Table_Primary", schema = "schema ")
#SecondaryTable(name = "Table_Secondary", schema = "schema ", pkJoinColumns = {#PrimaryKeyJoinColumn(name = "Table_Primary_Column", referencedColumnName = "Table_Secondary_Column")})
1) Try the following (I would expect this to work, but Hibernate may not play this way):
#Entity
#Table(name="part")
#SecondaryTable(name="supplement", pkJoinColumns ={#PrimaryKeyJoinColumn="id"})
public class Part{
#Id
#GeneratedValue
private Integer id;
private String poNo;
private String partNo;
private String partDesc;
private String eccNo;
#Column(table="supplement")
#Basic(optional=true)
private String vernderPartNo;
#Column(table="supplement")
#Basic(optional=true)
private String exportHSCCode;
...
getter and setter...
}
2) You'll need to change how your keying Part. You've defined its primary key as an auto incremented integer...that's gonna be your foreign key in the supplement table. This is actually how JPA wants you to do it (I say that because the JPA specification calls natural keys "legacy"). You have a couple options here:
remove the autoincrement from the Part entity and create a "composite key" class with just the poNo and partNo, and add that class as a field to Part. This will become your Part primary key, and will be the foreign key used in your supplement table.
Forget foreign keys and instead add a #UniqueConstraint to your Part for those two columns (this isn't going to fix your foreign key issue, but it does enforce the constraint you identified)

Native Query (JPA ) not reset and return the same old result

I have a native sql query as the following :
for (init i=0; i<=2 ; i++) {
String sql = "Select * from accounts where id = ?";
Query query = em.createNativeQuery(sql,AccountBean.class);
query.setParameter(1, i );
AccountBean accountBean = (AccountBean)query.getSingleResult();
}
For the first loop it works correctly but any loop after the first one returns the same result as the first one , i debug it, the parameter changed , it works correctly if i change
Query query = em.createNativeQuery(sql,AccountBean.class);
to
Query query = em.createNativeQuery(queryString);
Regards
Wish79
Every JPA entity must have a primary key. Your JPA entities may not properly reflect the primary key, if any, on the database table.
I ran into the same problem. In my model class I had only one class variable annotated with #Id. However, that was not an accurate reflection of the table itself, which has a composite primary key. Thus, my query results returned the correct number of rows, but each confoundingly contained the same values, even though the actual data was different in the db. For example, this query:
Query query = entityManager.createQuery
("SELECT tbl FROM Tbl tbl WHERE tbl.id = 100
and tbl.code in ('A','B','C')");
...returned 10 rows, each showing a code of 'A'. But in actuality 9 of those 10 rows had a different code value ('B' or 'C'). It seemed as if the results were being cached and/or the tbl.code predicate was ignored. (That happened whether I used JPQL or Native SQL.) Very confusing.
To fix this I added an additional #Id annotation to my model to reflect the composite primary key:
#Id
#Column(name = "Code")
public String getCode() {
return this.code;
}
Now the query returns the data correctly and the code select criteria is no longer effectively ignored.
Edit: Although the above worked for me, on further research it seems a better approach to configure a separate JPA Entity composite primary key class. See http://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cmp30cfg001.htm.
For example, here's an Entity class with an embedded primary key (see #EmbeddedId):
/**
* The persistent class for the SOME_TABLE database table.
*/
#Entity
#Table(name = "SOME_TABLE")
public class SomeTable implements Serializable {
#EmbeddedId
private SomeTablePk id;
#Column(name = "NUMBER_HRS")
private BigDecimal numberHrs;
...
...and here's the composite primary key class (see #Embeddable):
#Embeddable
public class SomeTablePk implements Serializable {
#Column(name = "SOME_ID")
private String someId;
#Column(name = "ANOTHER_ID")
private BigDecimal anotherId;
public String getSomeId() {
return someId;
}
...

JPA : Is there any way to run a simple SELECT statement that only access a few columns?

I'm new to JPA so forgive me if my question seems silly.
We have used JPA in our project. I see that every entity object has a direct mapping with a table and each row in the table is an object of that entity type.
But, suppose I only want to access one or two columns of a table, how do i go about doing it ? The reason I'm asking is because of the task i have in hand.
There are two tables. The first table has everything set up with JPA so that each row can be cast into an object type. The first table has a column that is referenced in the second table i.e. say, table A has column CLOTH_ID and Table B has columns CLOTH_ID and CLOTH_DESCRIPTION. CLOTH_ID is used in both Table A and B; But B has the CLOTH_DESCRIPTION columns which corresponds to CLOTH_ID.
I'm displaying Table A in my webpage but I also need to display : CLOTH_DESCRIPTION in my webpage. Is there a JPA oriented way to do this or Am i better off using regular JDBC to extract the CLOTH DESCRIPTION values ?
I assume you have the following setup:
#Entity
#Table(name="A")
class A {
#ManyToOne
#JoinColumn(name="CLOTH_ID")
private B cloth;
//...
}
#Entity
#Table(name="B")
class B {
#Id
#Column(name="CLOTH_ID")
private int id;
#Column(name="CLOTH_DESCRIPTION")
private String description;
//...
}
If you don't... you're doing it wrong (i.e. it is not idiomatic JPA usage). You have the following options:
Simply fetch A
In this case #ManyToOne relationship will be fetched eagerly by default as well. Then simply call in Java:
a.getCloth().getDescription()
Prefer this approach as it is the simplest and most idiomatic unless the number of columns in B is huge.
Use JPA query with custom columns:
SELECT a, a.b.description
FROM A a
WHERE a.id = :id
In this case the query returns List<Object[]>, where Object[] actually contains two elements: A and String.
Same as above but with custom DTO:
class Adto {
private final A a;
private final String description;
public Adto(A a, String description) {
this.a = a;
this.description = description;
}
}
And slightly modified query:
SELECT new Adto(a, a.b.description)
FROM A a
WHERE a.id = :id

Basic Hibernate/JPA Mapping question

I have to tables I want to map to each other.
I want to populate 2 drop down lists: code_r and code_l.
When i choose a value from code_r, code_l should display only certain records.
In my database I have 2 tables:
Table code_r
===================
CODE INT
LIBELLE VARCHAR
And
Table code_l
===================
ID BIGINT
CODE_R_ID INT
LIBELLE VARCHAR
One code_r can have multiple code_l associated with it (based on the code_r_id (not a defined as a Foreign key in the code_l definition). Of course, a code_l can only be associated to one code_r.
The following SQL query works fine:
SELECT *
FROM code_r r
left join `code_l` l on l.code_r_id = r.code;
How should I implement that using using JPA/Hibernate-3.5 annotations in the CodeR and CodeL classes??
Any help would be appreciated. Thanks in advance.
With Hibernate (and now standardized in JPA 2.0), you can use a unidirectional one-to-many association without a join table using a JoinColumn annotation:
Annotate the CodeR like this:
#Entity
public class CodeR {
#Id
private Integer code;
private String libelle;
#OneToMany
#JoinColumn(name="CODE_R_ID")
Set<CodeL> codeLs = new HashSet<CodeL>():
// getters, setters
}
And CodeL
#Entity
public class CodeL {
#Id
private Integer id;
private String libelle;
// getters, setters, equals, hashCode
}
And the JPQL query:
SELECT r FROM CodeR LEFT JOIN r.codeLs
in the CodeR class:
#OneToMany(mappedBy="code_r_id")
Collection elementsFromL;
in the CodeL class:
#ManyToOne
CodeR code_r_id;

Categories

Resources