I have simple entity class (irrelevant methods omitted):
#Entity
#Table(name="CONNECTIONS")
public class Connection implements Serializable {
#Id private Long id_track;
#Id private Long id_carrier;
#Id private Date date_out;
#Id private Time time_out;
private Date date_in;
private Time time_in;
private Double price;
...
}
I expect that JPA (in my case Eclipse implementation) creates TABLE CONNETIONS with composite primary key that consists of id_track, id_carrier, date_out and time_out columns but it adds addidional column id (of type integer) What do I do wrong?
I can not reproduce this. Are you sure JPA is creating your table?
Also ensure you have recompiled and redeployed your code.
Perhaps enable logging, and include what JPA provider and version you are using.
Are you using Glassfish?
Related
I'm working on a JavaEE application with EJB and JPA.
My Entities, are defined, for instance, like this:
#Entity
public class Utente implements Serializable {
#Id
#GeneratedValue
private int cod_utente;
private String nome_utente;
private String morada_utente;
#Temporal(TemporalType.DATE)
private GregorianCalendar dnasc_utente;
private int tel_utente;
private List<GregorianCalendar> agenda;
#OneToMany
#JoinColumn(nullable=true)
private List<Prescricao> lista_presc;
When I create entities Utente, the keys are generated sequentially starting from one. If I shut down the clients and server and execute them again, the "counter" of the key generator is reestablished. This results in an error because the application will try to create another Utente with primary key "1".
Can please someone help me solve this problem?
The code:
#Id
#GeneratedValue
private int cod_utente;
doesn't set a specific stategy to generate the values for the ID.
It is the same as this code:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int cod_utente;
GenerationType.AUTO means that the persistence provider (in Glassfish the default persistence provider is EclipseLink) should choose an appropriate strategy for the database you are using. It looks like the persistence provider is choosing a strategy which is restarting the values after a server restart in your case.
There are different generation strategies, you can find some detailed information in the EclipseLink Wiki.
I guess your best bet is to use a database sequence (GenerationType.SEQUENCE) to generate the ID values.
Example:
Create a database sequence named GEN_SEQUENCE (if you let the persistence provider generate your tables I guess you can also let it create the sequence somehow but this example will show how to do it manually), you should look for information on how to do that in the database you are using (probably something like CREATE SEQUENCE gen_sequence;). Change your code to this:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq_gen")
#SequenceGenerator(name = "my_seq_gen", sequenceName = "GEN_SEQUENCE")
private int cod_utente;
You can also use the same sequence for different classes.
Update:
For the #SequenceGenerator you can set an allocationSize, this value is the amount of sequence values which get reserved. The default value is 50. When you have a sequence which starts at 0, the first time a value is requested from the sequence, the sequence allocates (and reserves) the values 0-49 (or 1-50). These values can be used by the persistence provider until all values have been used, then the next 50 values (50-99 or 51-100) will get allocated and reserved. The sequence remembers the current position, so that it doesn't give out the same range twice if it is used by multiple classes.
For the value of the allocationSize you can keep the default, but this may produce gaps in the IDs. If a sequence range (e.g. 0-49) gets allocated (reserved) and only one or some of the values are used (e.g. 0, 1 and 2) the other values of this range (3-49) will get "lost" on server restart. The next time a range of values is allocated it will be 50-99, so the next ID in your table will be 50.
Now you have the following IDs in your table: 0,1,2,50. Normally this shouldn't be a problem, but you can also set the allocationSize to a lower value or to 1 to avoid creating such gaps.
See also:
what is the use of annotations #Id and #GeneratedValue(strategy = GenerationType.IDENTITY)? Why the generationtype is identity?
what is sequence (Database) ? When we need it?
The differences between GeneratedValue strategies
I am trying to set up a simple foreign key relation ship using JPA in a rather complex OSGi environment.
The two entities I want to use are structured in bundles like so:
masterbundle
|->org.masterpackage.persistence
|-> MasterEntityDto.java
slavebundle
|->org.slavepackage.persistence
|-> SlaveEntity.java
SlaveEntity want to refer to the MasterEntityDtolike so
#Entity(name = "SlaveEntity")
public class SlaveEntity {
#Id
#Column(name = "slaveID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne
#JoinColumn(name = "masterEntity_id")
private MasterEntity masterEntity;
// snip..
}
Now, this fails because masterbundle is not exporting the MasterEntityDto (or its package), I think. We are using the Service Aspect of OSGi, masterBundle is provide-interface-ing a service that is using the Dto instead of the Dto.
The exception I see when the bundle starts says, among other things org.osgi.framework.BundleException: Unresolved constraint in bundle slavebundle [121]: Unable to resolve 121.8: missing requirement [121.8] osgi.wiring.package;
Question: How do I create a #OneToOne relation from SlaveEntity to MasterEntityDto? Is this not possible in when using the OSGi service platform and I only expose services and not whole bundles / packages?
Edit1
As per request: MasterEntityDto has nothing fancy.
#Entity(name = "MasterEntityDto")
public class MasterEntityDto {
#Id
#Column(name = "id", length = 128)
private String masterId;
// snip
}
I would want JPA to make a SlaveEntity - table with columns SlaveId (which is this tables PK) and masterEntity_id which would act as foreign key, pointing to table MasterEntityDto's id column.
The packages containing domain classes (such as MasterEntityDto) do need to be exported, so that the JPA bundle can have visibility to instantiate them.
Because of this it is very important to keep such packages separated from other packages containing implementation/logic code, which should be private.
Isn't it possible to map xml to jpa entities using JAXB? Will Eclipselink Moxy be helpful?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Yes you can map JPA entities to XML, and the following are some ways that EclipseLink JAXB (MOXy) makes this easier.
1. Bidirectional Mappings
Customer
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
Address
import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
public class Address implements Serializable {
#Id
private long id;
#OneToOne
#JoinColumn(name="ID")
#MapsId
#XmlInverseReference(mappedBy="address")
private Customer customer;
}
For More Information
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
http://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-25.html
2. Mapping Compound Key Relationships
We normally think of mapping a tree of objects to XML, however JAXB supports using the combination of #XmlID/#XmlIDREF to map relationship between nodes representing a graph. The standard mechanism is one key, to one foreign key. JPA supports the concept of composite keys and so does MOXy using #XmlKey and #XmlJoinNodes (similar to #XmlJoinColumns in JPA).
Employee
#Entity
#IdClass(EmployeeId.class)
public class Employee {
#Id
#Column(name="E_ID")
#XmlID
private BigDecimal eId;
#Id
#XmlKey
private String country;
#OneToMany(mappedBy="contact")
#XmlInverseReference(mappedBy="contact")
private List<PhoneNumber> contactNumber;
}
PhoneNumber
#Entity
public class PhoneNumber {
#ManyToOne
#JoinColumns({
#JoinColumn(name="E_ID", referencedColumnName = "E_ID"),
#JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
})
#XmlJoinNodes( {
#XmlJoinNode(xmlPath="contact/id/text()", referencedXmlPath="id/text()"),
#XmlJoinNode(xmlPath="contact/country/text()", referencedXmlPath="country/text()")
})
private Employee contact;
}
For More Information
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JPA/CompoundPrimaryKeys
3. MOXy allows for Composite and Embedded Keys
JPA can also use embedded key classes to represent composite keys. MOXy also supports this style of composite keys.
For More Information
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JPA/EmbeddedIdClass
4. EclipseLink JAXB (MOXy) and EclipseLink JPA Have Shared Concepts
EclipseLink provides both JAXB and JPA implementations that share a common core. This means that they share many of the same concepts, such as:
Virtual Access Methods
EclipseLink supports the concept of virtual properties. This is useful when creating a multi-tenant application where you want per-tenant customizations. This concept is upported in both EclipseLink's JPA and JAXB implementations.
http://blog.bdoughan.com/2011/06/moxy-extensible-models-multi-tenant.html
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Extensibility
I have a number of ServiceDefinition entities. I'm trying to create a series of License entities that contain a reference to one or more ServiceDefinition entities;
#Entity
public class License {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
#Column(name="serial")
private int serialNumber;
#OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
protected List<ServiceDefinition> definitions;
<-- rest of class omitted -->
#Entity
public class ServiceDefinition implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
<-- rest of class omitted -->
When the database is instantiated JPA creates me a ServiceDefinition table, a License table and a License_ServiceDefinition table.
I have been able to add and update records into this structure, but when I try to delete a License enity, JPA deletes the entries from the License_ServiceDefinition table and the License table. Then JPA tries to delete from the ServiceDefinition table which I don't want.
The ServiceDefinition is a "Master" table and in the same way as an OrderHeader entity might contain a reference to a Customer entity and deleting the OrderHeader should not result in deletion of the Customer, I want to be able to delete a License and it's references to ServiceDefinition entities without deleting the ServiceDefinition itself. I hope that makes sense.
Is this possible or do I need to deal with this manually.
Regards
Regards
Just remove the cascade=CascadeType.ALL and orphanRemoval=true from the annotation.
orphanRemoval=true means that if a service definition is removed from the list of service definitions, it should be removed.
CascadeType.ALL means that every operation made on a license should be cascaded to each service definition in the list. So if you delete the license, the service definitions in the list are deleted in cascade.
Those attibutes have a meaning, and have consequences. Don't use them without understanding their meaning. And don't add them everywhere thinking you code might magically work better.
I'm asking and answering my own question, but i'm not assuming i have the best answer. If you have a better one, please post it!
Related questions:
How to set a backreference from an #EmbeddedId in JPA
hibernate mapping where embeddedid (?)
JPA Compound key with #EmbeddedId
I have a pair of classes which are in a simple aggregation relationship: any instance of one owns some number of instances of the other. The owning class has some sort of primary key of its own, and the owned class has a many-to-one to this class via a corresponding foreign key. I would like the owned class to have a primary key comprising that foreign key plus some additional information.
For the sake of argument, let's use those perennial favourites, Order and OrderLine.
The SQL looks something like this:
-- 'order' may have been a poor choice of name, given that it's an SQL keyword!
create table Order_ (
orderId integer primary key
);
create table OrderLine (
orderId integer not null references Order_,
lineNo integer not null,
primary key (orderId, lineNo)
);
I would like to map this into Java using JPA. Order is trivial, and OrderLine can be handled with an #IdClass. Here's the code for that - the code is fairly conventional, and i hope you'll forgive my idiosyncrasies.
However, using #IdClass involves writing an ID class which duplicates the fields in the OrderLine. I would like to avoid that duplication, so i would like to use #EmbeddedId instead.
However, a naive attempt to do this fails:
#Embeddable
public class OrderLineKey {
#ManyToOne
private Order order;
private int lineNo;
}
OpenJPA rejects the use of that as an #EmbeddedId. I haven't tried other providers, but i wouldn't expect them to succeed, because the JPA specification requires that the fields making up an ID class be basic, not relationships.
So, what can i do? How can i write a class whose key contains #ManyToOne relationship, but is handled as an #EmbeddedId?
I don't know of a way to do this which doesn't involve duplicating any fields (sorry!). But it can be done in a straightforward and standard way that involves duplicating only the relationship fields. The key is the #MapsId annotation introduced in JPA 2.
The embeddable key class looks like this:
#Embeddable
public class OrderLineKey {
private int orderId;
private int lineNo;
}
And the embedding entity class looks like this:
#Entity
public class OrderLine{
#EmbeddedId
private OrderLineKey id;
#ManyToOne
#MapsId("orderId")
private Order order;
}
The #MapsId annotation declares that the relationship field to which it is applied effectively re-maps a basic field from the embedded ID.
Here's the code for OrderId.