Ormlite Multiple PK on class I do not have control - java

I have a class that I cannot change which has multiple #Id (annotated in JPA annotation) fields and some other annotations that ormlite does not support. So I am creating the table using java code to annotate the class.
However, without the ability to add an extra field to the class, the UniqueCombo trick mentioned in Multiple primary keys - ORMlite does not work for me because for example:
class A {
#Id
int key1;
#Id
int key2;
}
with the following Java code to create ormlite table config:
DatabaseField f = new DatabaseField("key1");
f.setId(true);
f.setUniqueCombo(true);
fieldConfig.add(f);
f = new DatabaseField("key2");
f.setUniqueCombo(true);
fieldConfig.add(f);
if I set any of them as PK (setId(true)) then when the data are actually different, the DB will not be happy when I try to create another row with the same key. Are there any way to solve this problem without changing class A?

No, ORMlite allows only one field as a primary key.

Related

Persisting third-party classes with no ID's

Say I have the following Java class, which is owned by a vendor so I can't change it:
public class Entry {
private String user;
private String city;
// ...
// About 10 other fields
// ...
// Getters, setters, etc.
}
I would like to persist it to a table, using JPA 2.0 (OpenJPA implementation). I cannot annotate this class (as it is not mine), so I'm using orm.xml to do that.
I'm creating a table containing a column per field, plus another column called ID. Then, I'm creating a sequence for it.
My question is: is it at all possible to tell JPA that the ID that I would like to use for this entity doesn't even exist as a member attribute in the Entry class? How do I go about creating a JPA entity that will allow me to persist instances of this class?
EDIT
I am aware of the strategy of extending the class and adding an ID property it. However, I'm looking for a solution that doesn't involve extending this class, because I need this solution to also be applicable for the case when it's not only one class that I have to persist, but a collection of interlinked classes - none of which has any ID property. In such a scenario, extending doesn't work out.
Eventually, I ended up doing the following:
public class EntryWrapper {
#Id
private long id;
#Embedded
private Entry entry;
}
So, I am indeed wrapping the entity but differently from the way that had been suggested. As the Entry class is vendor-provided, I did all its ORM work in an orm.xml file. When persisting, I persist EntryWrapper.
I don't have much experience with JPA, but I wouldn't extend your base classes, instead I would wrap them:
public class PersistMe<T> {
#Id
private long id;
private T objToWrap;
public(T objToWrap) {
this.objToWrap = objToWrap;
}
}
I can't test it, if it doesn't work let me know so I can delete the answer.

Extend entity classes with composite keys in hibernate

In our company we have a strange database model which can't be modified because to many systems works with them. Up to know we have a straight java application which connects with hibernate to the database and loads the data. We have for each table one xml mapping file.
The strange thing about the database is that we do not have any primary keys. Most table have a unique index containing several columns.
Now we want to use an application server (jboss) and the ejb model. So I created a class like this:
#Entity
#Table (name = "eakopf_t")
public class Eakopf implements Serializable {
#Embeddable
public static class EakopfId implements Serializable {
private String mandant;
private String fk_eakopf_posnr;
// I removed here the getters and setters to shorten it up
}
#Id
private EakopfId id;
private String login;
// I removed the getters and setters here as well
}
This works perfect.
Because our customers have different versions of the database schema I thought about extending this class on each database release change. So each interface we create with java can decide which version of the table will be used.
Here is the extended table class
#Entity
#Table (name = "eakopf_t")
public class Eakopf6001 extends Eakopf implements Serializable {
private String newField;
// getters and setters
}
If I use Eakopf (the base version) it is working if I do something like that:
EakopfId id = new EakopfId();
id.setMandant("001");
id.setFk_eakopf_posnr("ABC");
Eakopf kopf = (Eakopf) em.find(Eakopf.class, id);
But if I do this:
EakopfId id = new EakopfId();
id.setMandant("001");
id.setFk_eakopf_posnr("ABC");
Eakopf6001 kopf = (Eakopf6001) em.find(Eakopf6001.class, id);
this exception occues
javax.ejb.EJBException: javax.persistence.PersistenceException:
org.hibernate.WrongClassException: Object with id:
de.entity.Eakopf$EakopfId#291bfe83 was not of the specified subclass:
de.entity.Eakopf (Discriminator: null)
Does anybody has an idea?
many greetings,
Hauke
Doing what you did means to Hibernate that you're storing two different kinds of entities in a single table. This is possible is you use a discriminator column. But if I understand correctly, you just want one kind of entity in the table : Eakopf6001. In this case, its base class should be annotated with #MappedSuperClass, not with #Entity.
I would suggest creating a class annotated with #MappedEntity (let's call it BaseEakopf), and two entities: EaKopf and EaKopf6001, each with their set of additional fields. Include one of the other of the entities in the list of mapped classes, depending on which one you want to use.
My personal opinion is that if you have multiple versions of your app, they should use the same entities, but with different fields. Your version control system would take care of these multiple versions, rather than your source code (i.e. have one set of source files per version of the app, rather than one single set of source files for all the possible versions).

Custom wrapper for id key

I want to wrap id in custom class. Like this
#Entity
#Table(name = "USERS")
public class User {
#EmbeddedId
UserId id;
}
#Embeddable
public class UserId implements Serializable {
private Long value;
}
The issue in auto generation value for UserId. What I should do to make #GeneratedValue on value be workable?
BTW, It would be great if id would be initialized automatically itself.
As far as I know Hibernate only generates values for a field marked as the #Id. I found this post and Hardy's answer supports this.
We have tried to do similar and managed it via a pre-insert listener. It was fairly complex and non-ideal though. Also you might find different behaviour on different database palatforms. Using Oracle sequences would mean that you need to assign the value pre-insert (Hibernate does a select to get the value and then an insert) but with MySQL the auto incrementing field would assign the value and hibernate does an insert to generate the auto generated value and then select to find out what the value was.

Is it possible to map a field in an Entity without defining any association?

I've got the following schema in DB (simplified)
MainTable(
ID primary key
SOMEFIELD
CODE_FK1 -- references OtherTable1 CODE (without declared foreign key)
CODE_FK2 -- references OtherTable2 CODE (without declared foreign key)
... Other fields used
)
OtherTable1(
CODE primary key
LABEL
... other fields not used
)
OtherTable2(
CODE primary key
LABEL
... other fields not used
)
I'm asking if there is any way to define my Entity for main table in order to use directly labels from my other tables, i.e without defining entities for these other table.
I cannot change the DB schema, which is really awful (there are labels/code couples everywhere, defined in multiples tables).
And If it was possible, this solution would allow to keep my code simple, since I don't really need these other entities.
I guess it would result something like that:
#Entity
public class MainEntity{
#Id
private Integer ID;
#Column(name="SOMEFIELD")
private String SomeField;
#SomeAnnotation to Join CODE_FK_1 with OtherTable1.CODE
#SomeAnnotation like #Column(name="LABEL", table="OtherTable1")
private String Label1;
#SomeAnnotation to Join CODE_FK_1 with OtherTable1.CODE
#SomeAnnotation like #Column(name="LABEL", table="OtherTable1")
private String Label1;
}
Thanks by advance for your help!
Another possibility would be using the #Formula annotation to fetch the value from the other table. This will automatically generate a subselect whenever you load your Entity.
I think you'll need something like this:
#Entity
public class MainEntity{
#Id
private Integer ID;
#Column(name="SOMEFIELD")
private String SomeField;
#Formula("(SELECT ot1.LABEL FROM OtherTable1 ot1 WHERE ot1.CODE = CODE_FK_1)")
private String Label1;
}
There is little information about this in the [Hibernate docs][1], so you may need some trial and error to get it right (but you should be able to work it out with hibernate.show_sql=true.
There are 2 possible downsides to this approach:
This is hibernate-specific code
This is plain SQL, and may thus be database-specific
HTH
[1]: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-property hibernate docs
You can use the #SecondaryTable annotation. See this example:
https://github.com/hibernate/hibernate-orm/blob/823a5c1ede1869fd97471e3b8ebe7ec4ac8068e4/hibernate-core/src/test/java/org/hibernate/test/annotations/join/Dog.java#L20-L24

Typesafe Primary Key in Hibernate/JPA

I am looking for a way to have a typesafe primary key for my entities using generics in Hibernate. Instead of doing this
#Entity
public class User{
#PrimaryKey
Long id
}
I was thinking of doing this...
#Entity
public class User{
#PrimaryKey
PrimaryKey<User,Long> id
}
Or take the type inference even further...
Any ideas? Has anybody ever tried this before? Would you do this by making your class PrimaryKey embeddable?
#Entity
public class User extends MyEntity<Long>//Primary key type{
#PrimaryKey
PrimaryKey<User> id;
}
While it is possible to use a PK class and to use it as a member of entities with the #EmbeddedId, this would typically make all your JQL queries and your Java code more verbose:
select a.addressKey.id from Address a
or
AddressKey addressKey = new AddressKey();
addressKey.setCountry("USA");
addressKey.setId(634);
Address a = entityManager.find(Address.class, addressKey);
So I would personally use this for a real composite key (i.e. not with a single attribute) only.
Actually, I'm really wondering what problem you are trying to solve because at the end, you will have to deal with a Long anyway. I don't really see the added value of a single attribute typesafe primary key.
If you are looking for a typesafe way to identify an entity, what about using its LazyLoadingProxy?

Categories

Resources