I have two entities A and B:
A.java:
...
public class A implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "IDA", nullable = false)
private Integer ida;
#Basic(optional = false)
#Column(name = "NAME", nullable = false, length = 30)
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "a")
private List<B> bList=new ArrayList();
public void addB(B bp){
bp.setA(this);
bList.add(bp);
}
...
B.java:
...
public class B implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected BPK bPK;
#Basic(optional = false)
#Column(name = "NAME", nullable = false, length = 30)
private String name;
#JoinColumn(name = "A_IDA", referencedColumnName = "IDA", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false)
private A a;
...
the bPK field is a Composite Primary Key:
#Embeddable
public class BPK implements Serializable {
#Basic(optional = false)
#Column(name = "IDB", nullable = false, length = 20)
private String idb;
#Basic(optional = false)
#Column(name = "A_IDA", nullable = false)
private int aIda;
public BPK() {
}
public BPK(String idb, int aIda) {
this.idb = idb;
this.aIda = aIda;
}
...
SQL code:
CREATE TABLE A (
idA INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
PRIMARY KEY(idA)
);
CREATE TABLE B (
idB VARCHAR(20) NOT NULL,
A_idA INTEGER UNSIGNED NOT NULL,
name VARCHAR(30) NOT NULL,
PRIMARY KEY(idB, A_idA),
FOREIGN KEY(A_idA)
REFERENCES A(idA)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);
the main code:
A a=new A(null,"A1");
BPK bpk=new BPK();
bpk.setIdb("b1");
a.addB(new B(bpk,"B1"));
EntityManager em=getEntityManager();
em.getTransaction().begin();
em.persist(a);
em.getTransaction().commit();
I get this error:
Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
[EL Warning]: 2012-03-26 01:29:16.724--UnitOfWork(1902320872)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "CONSTRAINT_42_1: PUBLIC.B FOREIGN KEY(A_IDA) REFERENCES PUBLIC.A(IDA)"; SQL statement:
Internal Exception: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "CONSTRAINT_42_1: PUBLIC.B FOREIGN KEY(A_IDA) REFERENCES PUBLIC.A(IDA)";...
the error indicates a violation of integrity constrains, but why?
a single possibility whether the insertion of the entity B is made before A...
Any help please?
Thank you in advance.
EDIT:
solved just replace this :
#JoinColumn(name = "A_IDA", referencedColumnName = "IDA", nullable = false, insertable = false, updatable = false)
by this one:
#MapsId("aIda")
finally B.java:
#NamedQuery(name = "B.findByName", query = "SELECT b FROM B b WHERE b.name = :name")})
public class B implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected BPK bPK;
#Basic(optional = false)
#Column(name = "NAME", nullable = false, length = 30)
private String name;
#MapsId("aIda")
#ManyToOne(optional = false)
private A a;
You have the A_AID field controlled by the aIda attribute in the Embeddable - that means this attribute must be set with the value from A before you can persist B.
If you are using using JPA 2.0, you can mark the #ManyToOne with the #MapsId("aIda") which will allow you to remove the #JoinColumn for it. This will make the JPA provider set the value in b.bPK.aIda with the value from A on persist.
If you are not using JPA 2,0, you can either set it yourself by first persisting A and then changing your addB method to also set B's bPK.aIda, or you can change the fields so that the JoinColumn is writable and make the bPK.aIda insertable=false, updatable=false.
Related
Let's imagine that we have two entities in the database. We have a simple Server with a unique Id:
PostgreSQL:
CREATE TABLE public.servers (
id bigint NOT NULL,
name character varying(64) NOT NULL
);
ALTER TABLE ONLY public.servers
ADD CONSTRAINT servers_pkey PRIMARY KEY (id);
Class entity:
#Entity
#Table(name = "servers")
public class Server {
#Id
private long id;
private String name;
#OneToMany(mappedBy = "server", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Channel> channels;
public Server() {}
public Server(String name) {
this.name = name;
channels = new ArrayList<>();
}
// Getters and Setters...
}
Each Server can have several Channels that also have a unique id and belong to a server:
PostgreSQL:
CREATE TABLE public.channels (
id bigint NOT NULL,
server_id bigint NOT NULL,
name character varying NOT NULL
);
ALTER TABLE ONLY public.channels
ADD CONSTRAINT channels_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.channels
ADD CONSTRAINT fkey_channel_server FOREIGN KEY (server_id) REFERENCES public.servers(id);
Class entity:
#Entity
#Table (name = "channels")
public class Channel {
#Id
private long id;
private String name;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "server_sn")
private Server server;
public Channel() {}
public Channel(Server server, String name) {
this.server = server;
this.name = name;
}
// Getters and Setters...
}
Next, I create a View in PostgreSQL:
CREATE VIEW public.summary AS
SELECT servers.s_snowflake AS server_id, channels.c_snowflake AS channel_id, channels.name FROM servers
JOIN channels ON servers.s_snowflake = channels.server_sn;
I want to get data from this view but I'm facing a problem on how to implement the class. I have tried something like this:
#Embeddable
class SummaryPK implements Serializable {
private long server_id;
private long channel_id;
}
#Entity
#Immutable
#Subselect("SELECT * FROM summary")
public class Summary {
#EmbeddedId
private SummaryPK summaryPK;
#MapsId("server_id")
#ManyToOne(fetch = FetchType.LAZY, targetEntity = Server.class)
#JoinColumn(name = "id", insertable = false, updatable = false)
private Server server;
#MapsId("channel_id")
#ManyToOne(fetch = FetchType.LAZY, targetEntity = Channel.class)
#JoinColumn(name = "id", insertable = false, updatable = false)
private Channel channel;
private String name;
// Getters and Setters
}
In the program, I want to receive a list of Entity, for example, by passing the Server ID. Any idea how to implement a working structure here?
Fixed the problem, there were incorrect id in JoinColumn:
#JoinColumn(name = "server_id", insertable = false, updatable = false)
#JoinColumn(name = "channel_id", insertable = false, updatable = false)
I have two table:
CREATE TABLE [LeTYPE](
[LeNAME] [varchar](100) NOT NULL,
[Le_DESC] [varchar](500) NULL,
[LeFOR] [varchar](50) NOT NULL,
CONSTRAINT [PK_LeTYPE] PRIMARY KEY CLUSTERED
(
[LeNAME] ASC
)
)
CREATE TABLE [Le](
[SN] [int] IDENTITY(1,1) NOT NULL,
[LeNAME_FK] [varchar](100) NOT NULL,
[Le_SN] [int] NULL,
[LOWERRANGE] [float] NOT NULL,
[UPPERRANGE] [float] NOT NULL,
[Le_DESC] [varchar](500) NULL,
[COLOR] [varchar](45) NULL,
CONSTRAINT [Le_pk] PRIMARY KEY CLUSTERED
(
[SN] ASC
))
GO
ALTER TABLE [Le] WITH CHECK ADD CONSTRAINT [FK_Le_LeTYPE] FOREIGN KEY([LeNAME_FK])
REFERENCES [LeTYPE] ([LeNAME])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [Le] CHECK CONSTRAINT [FK_Le_LeTYPE]
GO
One tuple in LETYPE will have many LE.
JPA Entity generated by netbeans:
public class Letype implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(nullable = false, length = 100)
private String Lename;
#Size(max = 500)
#Column(name = "Le_DESC", length = 500)
private String LeDesc;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(nullable = false, length = 50)
private String Lefor;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "LenameFk", fetch = FetchType.LAZY)
private List<Le> LeList;
}
public class Le implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(nullable = false)
private Integer sn;
#Column(name = "Le_SN")
private Integer LeSn;
#Basic(optional = false)
#NotNull
#Column(nullable = false)
private double lowerrange;
#Basic(optional = false)
#NotNull
#Column(nullable = false)
private double upperrange;
#Size(max = 500)
#Column(name = "Le_DESC", length = 500)
private String LeDesc;
#Size(max = 45)
#Column(length = 45)
private String color;
#JoinColumn(name = "LeNAME_FK", referencedColumnName = "LeNAME", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Letype LenameFk;
}
Now, What I wanted was if I add a LETYPE from JSF view I would like to add multiple LE also at the same time.
LETYPE
-LE1
-LE2
-LE3
The structure of entities generated by netbean has letypeList with in Le and not the opposite.
Is my database structure wrong or How to do it right?
Yes i feel like you got wrong relationship in database between LE and LETYPE.
Current relation from JPA perspective is treated as One LE can have Many LETYPE that is why you see below code in LE entity class.
#OneToMany(mappedBy = "LeFk")
private List<Letype> letypeList;
But it is wrong, you need Reverse relation i.e, One LETYPE can have Many LE (One-To-Many).
Basically your database structure is wrong I guess, you have to maintain FK column in LE table, where as currently you maintaining in LETYPE.
In database world, FK column always resides in Many side , in your case i.e. LE table.
What to do now
Remove FK column in LETYPE table
Add FK column in LE table referring to LETYPE table primary key
Generate JPA Entity again
Then you see right JPA code with right relation ship.
I hope then you should be able to do what you need.
"What I wanted was if I add a LETYPE from JSF view I would like to add multiple LE also at the same time" means that the LETYPE can be seen as the component class, and the LE as the composite class, so you should reverse the mapping annotations. To illustrate this and what #Jayasagar well explained in addition, the two classes's forms look like :
Letype.java :
public class Letype implements Serializable {
...
#OneToMany(mappedBy="letype")
private List<Le> les;
}
Le.java :
public class Le implements Serializable {
...
#ManyToOne
#JoinColumn(name = "Letype_FK", referencedColumnName = "LENAME")
private Letype letype;
}
I have a problem with persisting new objects to the database. I'm using Eclipselink and Postgresql. When I'm trying to add a new Merchandise, cascade adds also Price object.
Price.java
#Entity
#Table(name = "Prices")
public class Price implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(updatable = false)
private int id;
#Column(updatable = false, nullable = false)
private float value;
#Column(updatable = false, nullable = false)
private Date startDate;
#Column(updatable = false, nullable = true)
private Date endDate;
#ManyToOne(targetEntity=Merchandise.class,cascade=CascadeType.ALL)
#JoinColumn(name="id",nullable = false,updatable = false,insertable=false)
private Merchandise merchandiseId;
#Column(updatable = false, nullable = true)
private float valueBulk;
#Column(updatable = false, nullable = true)
private float valueRetail;
#Column(updatable = false, nullable = true)
private float makeupPercent;
#Column(updatable = false, nullable = true)
private float makeupForce;
Merchandise.java
#Entity
#Table(name="Merchandises")
public class Merchandise implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(updatable = false)
private int id;
#Column(updatable = false)
private int externalId;
#Column(unique = false, nullable = false, updatable = true)
private String name;
#Column(unique = false, nullable = true, updatable = true)
private int available;
#Column(unique = false, nullable = true, updatable = true)
private String description;
#OneToMany(targetEntity = Price.class, mappedBy = "merchandiseId",cascade = CascadeType.PERSIST)
private List<Price> prices;
#OneToMany(targetEntity = MerchandiseCategory.class, mappedBy = "merchandiseId",cascade = CascadeType.PERSIST)
private List<MerchandiseCategory> merchandiseCategories;
#OneToMany(targetEntity = MerchandiseOrder.class, mappedBy = "merchandiseId",cascade=CascadeType.PERSIST)
private List<MerchandiseOrder> merchandiseOrders;
#OneToMany(targetEntity = MerchandiseDiscount.class, mappedBy = "merchandiseId",cascade=CascadeType.PERSIST) //#61
private List<MerchandiseDiscount> discounts; //#61
my code in facede looks like this:
Dao dao = new DAO();//begins transaction etc.
Merchandise m = new Merchandise;
m.set..//setting all needed fields
List<Price> list = new ArrayList<Price>();
Price p = new Price();
p.set..//setting all needed fields
p.setMerchandiseID(m);
list.add(p);
m.setPrices(list);
dao.addMerchandise(m);//persisting
This gets mean error (in Polish base so I'll try to translate it): foreign key restriction violation - Key (id)=(356) is not present in merchandises.
I think this is problem with generating id, id fiels is always replaced by generated id, and i think they are different, but in this case should be the same
Your Price class uses its "id" field as the as the foreign key to Merchandise. You have also marked the ID attribute mapping to be generated, so it will always be different than what is in Merchandise. Did you intend Price to use its foreign key to Merchandise as the primary key? If so, you need to remove the #GeneratedValue from Price and either
1) need to persist Merchandise first, flush so that its primary key is assigned, and then set the value into p.setId() as well as calling p.setMerchandiseID(m).
or
2) use JPA 2.0's derived ID capability and mark Price's merchandiseId attribute as either #Id (and remove the int id as it isn't needed), or use #MapsId. #Mapsid will allow JPA to set the id value from Merchandise automatically when it is assigned a value.
Some info: http://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/DerivedIdentifiers
http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/mappedbyid
If you meant for Price to have its own independent primary key, you need to add a foreign key in the price table:
#ManyToOne(targetEntity=Merchandise.class,cascade=CascadeType.ALL)
#JoinColumn(name="fk_merchandiseid",nullable = false)
private Merchandise merchandiseId;
I need help to understand how ORM works. Here is the scenario that is very common. I have two main tables Organization and RelatedParty which have to be in many to many relation. But there is also relation_type attribute that defines what kind of relation exists between Organization and Relatedparty.
Here are my entity classes:
Organization:
#Entity
#Table(name = "organization", catalog = "...", schema = "")
#XmlRootElement
public class Organization implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "organization_id", nullable = false)
private Integer organizationId;
#Column(name = "organization_name", nullable = false)
private String organizationName;
#OneToMany(cascade = {CascadeType.ALL}, mappedBy = "organization")
private List<Organdrelatedparty> organdrelatedpartyList;
...
//getter setter methods
Organdrelatedparty: which uses composite primary key OrgandrelatedpartyPK
#Entity
#Table(name = "organdrelatedparty", catalog = "...", schema = "")
#XmlRootElement
public class Organdrelatedparty implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected OrgandrelatedpartyPK organdrelatedpartyPK;
#JoinColumn(name = "relatedParty_id", referencedColumnName = "relatedParty_id", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false, cascade= {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private Relatedparty relatedparty;
#JoinColumn(name = "orgRelation_id", referencedColumnName = "orgRelation_id", nullable = false)
#ManyToOne(optional = false)
private ParOrgrelationtype orgRelationid;
#JoinColumn(name = "organization_id", referencedColumnName = "organization_id", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false)
private Organization organization;
...
//getter setter methods
OrgandrelatedpartyPK
#Embeddable
public class OrgandrelatedpartyPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "relatedParty_id", nullable = false)
private int relatedPartyid;
#Basic(optional = false)
#NotNull
#Column(name = "organization_id", nullable = false)
private int organizationId;
...
//getter setter methods
RelatedParty: which is in unidirectional oneToMany relationship with organdRelatedParty class. In other word that relatedParty entity has no knowledge about organdRelatedParty entity that is on the other side.
#Entity
#Table(name = "relatedparty", catalog = "...", schema = "")
#XmlRootElement
public class Relatedparty implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "relatedParty_id", nullable = false)
private Integer relatedPartyid;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "firstName", nullable = false, length = 100)
private String firstName;
#Size(max = 100)
#Column(name = "lastName", length = 100)
private String lastName;
#Basic(optional = false)
#NotNull
#Column(name = "isForeign", nullable = false)
private boolean isForeign;
...
//getter setter methods
For insertion, if I persist new Organization Entity, it cascades persist activity to new OrgandrelatedParty which also cascades persist activity to new RelatedParty. So all the related entities are persisted and it works fine.
For updating, User is expected to change existing organization and relatedParty entities and also add new relatedParty to organization. So we prefer to delete all OrgandrelatedParties first and add new relatedParties and edited relatedParties again after that.
This is our method that handles updating: We pass new organization and also all new and old relatedParties as a list to method:
firs we delete all old OrgAndRelatedParties then we create again all relatedParties in list as new OrgandrelatedParties. This is main method to update organization.
public void updateOrganization(Organization newOrganization, List<Relatedparty> newShareList) throws ControlException {
try{
tx.begin();
this.updateOrgAndRelatedShares(newOrganization, newShareList);
customerController.updateOrganization(newOrganization);
tx.commit();
}catch(ControlException ex){
...
customerController's updateOrganization method does first find old Organization by find method of entity manager then copies all attributes of new organization to old then merges old organization and flush:
public void updateOrganization(Organization newOrganization)
{
Organization preOrganization = em.find(Organization.class, newOrganization.getOrganizationId);
preOrganization.setOrganizationId(newOrganization.getOrganizationId);
preOrganization.setOrganizationName(newOrganization.getOrganizationName);
em.merge(preOrganization);
em.flush();
}
here are other methods:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void updateOrgAndRelatedShares(Organization org, List<Relatedparty> shareList) throws ControlException
{
for(Iterator<Organdrelatedparty> it = org.getOrgandrelatedpartyList().iterator(); it.hasNext();)
{
Organdrelatedparty op = it.next();
it.remove();
op.setOrganization(null);
op.setRelatedparty(null);
deleteOrgRelated(op);
}
org.getOrgandrelatedpartyList().clear();
for(Relatedparty relatedParty: shareList){
int parOrgRelationTypeId = relatedParty.getIsPerson() ? 1:2;
createOrgAndRelatedParty(org, relatedParty, parOrgRelationTypeId);
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteOrgRelated(Organdrelatedparty org) throws ControlException{
try{
org = em.find(Organdrelatedparty.class, org.getOrgandrelatedpartyPK());
em.remove(org);
em.flush();
}
catch(Exception ex){
Logger.getLogger(RelatedpartyController.class.getName()).log(Level.SEVERE, null, ex);
throw new ControlException("Couln't delete org relation", ex);
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void createOrgAndRelatedParty(Organization org, Relatedparty relatedParty, int parOrgRelationTypeId) throws ControlException{
if(findRelatedPartyByRegNum(relatedParty.getRegisterNumber()) == null || relatedParty.getRelatedPartyid() == null){
createRelated(relatedParty);
}else{
relatedParty = updateRelatedParty(relatedParty);
}
Organdrelatedparty preOrp = new Organdrelatedparty(relatedParty.getRelatedPartyid(),
preOrp.setOrganization(org);
preOrp.setRelatedparty(relatedParty);
preOrp.setOrgRelationid(prepareOrgandRelatedPartyType(parOrgRelationTypeId));
org.getOrgandrelatedpartyList().add(preOrp);
}
And my question is when I merge organization entity with new List organdrelatedpartyList
it throws exception like this:
SEVERE: java.lang.IllegalArgumentException: Cannot merge an entity that has been removed: mn.bsoft.crasmonclient.model.Organdrelatedparty[ organdrelatedpartyPK=mn.bsoft.crasmonclient.model.OrgandrelatedpartyPK[ relatedPartyid=71, organizationId=19 ] ]
I found out that eclipseLink does persist operation first then remove operations. So I think that it tries to insert organdrelatedparty entity that has same composite id with entity which was not deleted previously from database. I flushes every time I remove old organdrelatedparties. But it doesn't help. What is the solution? Any idea guys.
I'm using jpa 2.0; eclipseLink as provider and glassfish 3.1.2
You seem to be making these a lot more complicated than they need to be.
Why don't you just remove the Organdrelatedparty that have been removed, instead of deleting all of them, then reincarnating some of them? Reincarnating objects, especially in the same transaction is normally a bad idea.
The error that is occurring is on merge() according to the code you included you are only call merge in updateOrgAndRelatedShares(), so I don't see how this object is removed at this point? Or is your code different than you show, please include the exception stack.
You updateOrganization() method is bad, it updates the objects Id, which you should never do. Also it calls merge for no reason, it already changed the object.
Also I would normally recommend using an IdClass instead of an EmbeddedId, and recommend using TABLE or SEQUENCE id generation instead if IDENTITY.
I need help with this. With code is more clear, this is my function to persist:
public String finalizarCompra() {
Pedido pedido = new Pedido();
pedido.setEstado("almacen");
pedido.setFechaVenta(new Date());
pedido.setIdUsuario(loginBean.getUsuario());
Producto p;
Integer i;
DetPedido detPedido;
List<DetPedido> lista = new ArrayList<>();
for (Map.Entry e : productos.entrySet()) {
detPedido = new DetPedido();
p = (Producto) e.getKey();
i = (Integer) e.getValue();
detPedido.setProducto(p);
detPedido.setCantidad(i);
detPedido.setPrecioUnidad(p.getPrecioUnidad());
detPedido.setPedido(pedido);
lista.add(detPedido);
detPedidoBean.insert(detPedido);
}
pedido.setDetPedidoCollection(lista);
pedidoBean.insert(pedido);
return "";
}
This is my Pedido Entity:
#Entity
public class Pedido implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID_PEDIDO")
private Integer idPedido;
#Basic(optional = false)
#NotNull
#Column(name = "FECHA_VENTA")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaVenta;
#Column(name = "FECHA_ENVIO")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaEnvio;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(name = "ESTADO")
private String estado;
#JoinColumn(name = "ID_USUARIO", referencedColumnName = "ID_USUARIO")
#ManyToOne(optional = false)
private Usuario idUsuario;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "pedido")
private Collection<DetPedido> detPedidoCollection;
// Getters and Setters //
This is my DetPedido Entity:
#Entity
public class DetPedido implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected DetPedidoPK detPedidoPK;
#Basic(optional = false)
#NotNull
#Column(name = "CANTIDAD")
private Integer cantidad;
#Basic(optional = false)
#NotNull
#Column(name = "PRECIO_UNIDAD")
private Double precioUnidad;
#JoinColumn(name = "ID_PRODUCTO", referencedColumnName = "ID_PRODUCTO", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Producto producto;
#JoinColumn(name = "ID_PEDIDO", referencedColumnName = "ID_PEDIDO", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Pedido pedido;
// Getters and Setters //
And this is my DetPedidoPK:
#Embeddable
public class DetPedidoPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "ID_PEDIDO")
private Integer idPedido;
#Basic(optional = false)
#NotNull
#Column(name = "ID_PRODUCTO")
private Integer idProducto;
// Getters and Setters //
The Entities ara generated automatically from the Database, also DetPedidoPK, and now I don't know how to save a Pedido. I tried with the code above, but it doesn't work.
Can anybody help me?
Greetings.
If you are using JPA 1.0 and this entity model, then you will need to persist and flush both Producto and Pedido instances to have their IDs assigned before you can persist the DetPedido instance that will reference them. Once that is done, you will need to manually set the id values in DetPedido's DetPedidoPK instance so that they match the referenced Producto and DetPedido key values. You cannot insert DetPedido without the DetPedidoPK values having been set.
JPA 2.0 supports derived IDs, which allows marking the relationship as either #ID or #MapsId, indicating that the ID values should be pulled from the joincolumn associated to the relationship. In this case, it would become:
#ManyToOne(optional = false)
#MapsId("idProducto")
private Producto producto;
#ManyToOne(optional = false)
#MapsId("idPedido")
private Pedido pedido;
If you wanted, you could do away with the embeddable within DetPedido and just mark the relationships as the #Id, and because it is composite you would use the DetPedidoPK as the PK class.