EclipseLink sequential numbered ID's using GenerationType.Identity - jpa

Extending this question Why does eclipselink consume the whole allocationSize each time it's rebooted?
I would like to know what a proper solution for this problem is, the only answer in that post suggests switching to an IDENTITY strategy which i have done but i cannot see the changes. The allocation size of 50 is still in affect. Does anyone have any examples on how to generate sequential identifiers (1, 2, 3) based on each entity (table) and not a single sequence accessible by all tables?

You have the TableGenerator annotation for that purpose.
#Entity
public class Employee {
#Id
#TableGenerator(name="TABLE_GEN", table="SEQUENCE_TABLE", pkColumnName="SEQ_NAME",
valueColumnName="SEQ_COUNT", pkColumnValue="EMP_SEQ", allocationSize = 500, initialValue = 1)
#GeneratedValue(strategy=GenerationType.TABLE, generator="TABLE_GEN")
private long id;
...
}
#Entity
public class PaySlip {
#Id
#TableGenerator(name="SECOND_TABLE_GEN", table="SECOND_SEQUENCE_TABLE", pkColumnName="SEQ_NAME",
valueColumnName="SEQ_COUNT", pkColumnValue="SECOND_EMP_SEQ", allocationSize = 500, initialValue = 1)
#GeneratedValue(strategy=GenerationType.TABLE, generator="SECOND_TABLE_GEN")
private long id;
...
}
Make sure that all the name/*table* and pkColumnValue fields value are unique.
Reference
Sequence Strategies

Related

How to define custom sequence generator used for Id (primary) in JPA?

My application is using JPA for persisting data to Database.
The application has to generate Custom(encoded) sequence for performance reasons.
By default JPA seems to generate Ids for an entity using some sequence.
How to override default sequence generator with customer sequence generator in Java ? I want to have sequence generator in Java as I have a separate logic for that.
This is how you go with the custom sequence:
#Id
#SequenceGenerator(name = "pet_seq",
sequenceName = "pet_sequence",
initialValue = 1, allocationSize = 20)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pet_seq")
#Column(name = "id", nullable = false)
private Long id;
In this case it will use pet_sequence instead of the default one. Also you can read this article for a better understanding of this subject.

Spring JPA Entities: related problems of Ignite error, LAZY fetching, and too-m, minimizing database use and working with Ignite

I'm writing some entity relationships using Spring Data and Java. I have this pair of classes (edited):
Subject:
#Entity
#Table(name = "SUBJECT")
// Lombok, etc., attributes removed
public class Subject {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "ID", updatable = false, nullable = false)
#JsonProperty("id")
private Long id;
#OneToMany(targetEntity = SubjectResource.class, mappedBy = "subject", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<SubjectResource> resources;
}
SubjectResource:
#Entity
#Table(name = "SUBJECT_RESOURCE")
// Lombok, etc., attributes removed
public class SubjectResource {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "ID", updatable = false, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SUBJECT_ID")
private Subject subject;
}
I'm trying to solve these issues:
Question 1: Can I manipulate #OneToMany or #ManyToOne to NOT have the child class recurse its parent?
Fetch of resources returns subject data:
/subject/101:
{"id":101,"resources":[{"id":1001,"subject":101},{"id":1002,"subject":101},{"id":1003,"subject":101},{"id":1004,"subject":101}]}
/subjectResource/1001:
{id:1001,subject:{"id":101,"resources":[{"id":1001,"subject":101},{"id":1002,"subject":101},{"id":1003,"subject":101},{"id":1004,"subject":101}]}}
That is, /subjectResource/1001 returns its ID and the entire /subject/101 query.
How can I have just the subjectResource data, without its parent?
Question 2: Through #OneToMany or #ManyToOne can I get Hibernate to fetch on a "1" (O(1)) basis?
When /subjects does its thing, it works with Hibernate on a "n+1" (O(n)) basis: 1 fetch of subjects, n fetches of resources, one for each subject ID.
I could force a single fetch through a fancy repository #Query annotation ("select s from subject s left join fetch s.resources"). But that means putting the subject : subject_resource definitions in two places, etc.
Can JPA implementation / Hibernate be forced to do a join, and thus make only one database call, through annotation within an entity class?
Question 3: How do I get my Spring Data / Spring Repository to cooperate with Ignite, and have the cache return the data it already had on the first call?
I'm usng FetchType.LAZY, as all good pupils do. I'm also storing things in Apache Ignite. For /subject/101 the initial call fetches everything OK, returning it in JSON. But the second call gets from the Ignite cache, which complains about being out of transaction.
How do get my LAZY fetches to cooperate with Ignite?
Thanks,
Jerome.

JPA one-to-one relationship without column mapping

I have a couple of entities with one-to-one relationships as such:
#Entity(name="stores")
public class Store implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.AUTO )
#Column(name="id")
private int id ;
// How should I set goal ?
private Goal goal ;
}
and:
#Entity(name="storeGoals")
public class Goal {
#Id
#GeneratedValue(strategy= GenerationType.AUTO )
#Column(name="goalId")
private int id ;
#OneToOne()
#JoinColumn(name = "storeId")
private Store store ;
}
My problem is how can I set the "goal" field in the Store entity?
Normally, I would do something like:
#Entity(name="stores")
public class Store implements Serializable {
...
#OneToOne()
#JoinColumn(name = "goalId")
private Goal goal ;
...
but in this case I can't, because the underlying "stores" table belongs to another application and can't be modified (by adding a "goalId" column).
What I need is for an instance of Store to be able to lookup its goal by finding a record in the storeGoals table that has the same storeId (Realizing of course that I could run into referential integrity issues...)
Any ideas on how to do that?
Thanks!
You might be looking for what is known as a bidirectional OneToOne relationship. This works the same as a bidirectional ManyToMany or OneToMany/ManyToOne relationship in that one side 'owns' the relationship and has control over setting the value in the foreign key; the other specifies it is 'mappedby' the other side, and so operates as if it is read-only. Both sides need to be kept in synch with any changes manually though; if you set one side but do not reflect the change in the other, JPA will not fix this for you.
In this case:
public class Store implements Serializable {
..
#OneToOne(mappedby="store")
private Goal goal ;
}

Adding entity doesn't refresh parent's collection

the question and problem is pretty simple, though annoying and I am looking for a global solution, because it's application-wide problem for us.
The code below is really not interesting but I post it for clarification!
We use PostgreSQL database with JPA 2.0 and we generated all the facades and entities, of course we did some editing but not much really.
The problem is that every entity contains a Collection of its children, which however (for us only?) is NOT updated after creation a children element.
The objects are written to database, you can select them easily, but what we really would like to see is the refreshed collection of children in parent object.
Why is this happening? If we (manually) refresh the entity of parent em.refresh(parent) it does the trick but it would mean for us a lot of work in Facades I guess. But maybe there is no other way?
Thanks for support!
/* EDIT */
I guess it has to be some annotation problem or cache or something, but I've already tried
#OneToMany(mappedBy = "idquestion", orphanRemoval=true, fetch= FetchType.EAGER)
and
#Cacheable(false)
didn't work properly.
/* EDIT */
Some sample code for understanding.
Database level:
CREATE TABLE Question (
idQuestion SERIAL,
questionContent VARCHAR,
CONSTRAINT Question_idQuestion_PK PRIMARY KEY (idQuestion)
);
CREATE TABLE Answer (
idAnswer SERIAL,
answerContent VARCHAR,
idQuestion INTEGER,
CONSTRAINT Answer_idAnswer_PK PRIMARY KEY (idAnswer),
CONSTRAINT Answer_idQuestion_FK FOREIGN KEY (idQuestion) REFERENCES Question(idQuestion)
);
Than we have generated some Entities in Netbeans 7.1, all of them look similar to:
#Entity
#Table(name = "question", catalog = "jobfairdb", schema = "public")
#XmlRootElement
#NamedQueries({ BLAH BLAH BLAH...})
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "idquestion", nullable = false)
private Integer idquestion;
#Size(max = 2147483647)
#Column(name = "questioncontent", length = 2147483647)
private String questioncontent;
#OneToMany(mappedBy = "idquestion", orphanRemoval=true)
private Collection<Answer> answerCollection;
Getters... setters...
We use (again) generated facades for them, all implementing AbstractFacade like:
public abstract class CCAbstractFacade<T> {
private Class<T> entityClass;
public CCAbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
The father entity is updated automatically if you use container managed transactions and you fetch the collection after the transaction is complete. Otherwise, you have to update yourself the collection.
This article explains in detail this behaviour: JPA implementation patterns: Bidirectional associations
EDIT:
The simplest way to use Container Managed Transactions is to have transaction-type="JTA" in persistence.xml and use Container-Managed Entity Managers.
You seem to be setting the ManyToOne side, but not adding to the OneToMany, you have to do both.
In JPA, and in Java in general you must update both sides of a bi-directional relationship, otherwise the state of your objects will not be in sync. Not doing so, would be wrong in any Java code, not just JPA.
There is no magic in JPA that will do this for you. EclipseLink does have a magic option for this that you could set through a customizer (mapping.setRelationshipPartnerAttributeName()), but it is not recommended, fixing your code to be correct is the best solution.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Object_corruption.2C_one_side_of_the_relationship_is_not_updated_after_updating_the_other_side

Why is this JPA 2.0 mapping giving me an error in Eclipse/JBoss Tools?

I have the following situation:
(source: kawoolutions.com)
JPA 2.0 mappings (It might probably suffice to consider only the Zip and ZipId classes as this is where the error seems to come from):
#Entity
#Table(name = "GeoAreas")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)
public abstract class GeoArea implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
protected Integer id;
#Column(name = "name")
protected String name;
...
}
#Entity
#Table(name = "Countries")
#DiscriminatorValue(value = "country")
public class Country extends GeoArea
{
#Column(name = "iso_code")
private String isoCode;
#Column(name = "iso_nbr")
private String isoNbr;
#Column(name = "dial_code")
private Integer dialCode = null;
...
}
#Entity
#Table(name = "Zips")
#IdClass(value = ZipId.class)
public class Zip implements Serializable
{
#Id
#Column(name = "code")
private String code;
#Id
#ManyToOne
#JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null;
...
}
public class ZipId implements Serializable
{
private String country;
private String code;
...
}
Pretty simple design:
A country is a geo area and inherits the ID from the root class. A ZIP code is unique within its country so it combines an ISO code plus the actual ZIP code as PK. Thus Zips references Countries.iso_code, which has an alternative unique, not-null key on it (reference to non-primary key column!). The Zip.country association gets an #Id annotation and its variable name is the same as the one in its ID class ZipId.
However I get this error message from within Eclipse (also using JBoss Tools):
Validation Message:
"The attribute matching the ID class attribute country does not have the correct type java.lang.String"
Why is this wrong in JPA 2.0 syntax (see #Id annotation on Zip.country)? I don't think it is. After all the types of Zip.country and ZipId.country can't be the same for JPA 2 because of the #Id annotation on the #ManyToOne and the PK being a simple integer, which becomes the ID class counterpart. Can anyone check/confirm this please?
Could this be a bug, probably in JBoss Tools? (Which software component is reporting the above bug? When putting the 3 tables and entity classes into a new JavaSE project there's no error shown with the exact code...)
Answering own question...
The way I modeled the reference, I use a String because the FK points to the iso_code column in the Countries table which is a CHAR(2), so basically my mapping is right. However, the problem is that JPA 2.0 doesn't allow anything but references to primary key columns. This is what the Eclipse Dali JPA validator shows.
Taken from "Pro JPA 2.0" by Keith/Schincariol p.283 top, "Basic Rules for Derived Identifiers" (rule #6): "If an id attribute in an entity is a relationship, then the type of the matching attribute in the id class is of the same type as the primary key type of the target entity in the relationship (whether the primary key type is a simple type, an id class, or an embedded id class)."
Personal addendum:
I disagree with JPA 2.0 having this limitation. JPA 1.0 mappings allow references to non-PK columns. Note, that using JPA 1.0 mappings instead isn't what I'm looking for. I'd rather be interested in the reason why this restriction was imposed on JPA 2.0. The JPA 2.0 is definitely limiting.
I'd say focus your attention on the CompoundIdentity relationship. See this question, and my answer there
Help Mapping a Composite Foreign Key in JPA 2.0
ZipId has no "country" field in your case
I have not tested your code, but it looks pretty much related to the use of the #PrimareKeyJoinColumn annotation.
The JPA 2.0 specification in section 11.1.40 states:
The PrimaryKeyJoinColumn annotation is
used to join the primary table of an
entity subclass in the JOINED mapping
strategy to the primary table of its
superclass; it is used within a
SecondaryTable annotation to join a
secondary table to a primary table;
and it may be used in a OneToOne
mapping in which the primary key of
the referencing entity is used as a
foreign key to the referenced
entity[108].
The example in the spec looks like your case.
#Entity
#Table(name="CUST")
#Inheritance(strategy=JOINED)
#DiscriminatorValue("CUST")
public class Customer { ... }
#Entity
#Table(name="VCUST")
#DiscriminatorValue("VCUST")
#PrimaryKeyJoinColumn(name="CUST_ID")
public class ValuedCustomer extends Customer { ... }
I hope that helps!