JPA entity and Database Table mapping Validation constraint(s) violated - jpa

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;
}

Related

Hibernate: getting entity from PostgreSQL view

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)

Unable to create unique key constraint - Make sure that you use the correct column name which depends on the naming strategy in use

The full error message is:
Unable to create unique key constraint (aircraft_series_id, service_enum) on table aircraft_service: database column 'service_enum' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
My entity is specified as:
#Entity
#Table(uniqueConstraints = { #UniqueConstraint(columnNames = { "aircraft_series_id", "service_enum" }) })
#Getter
#Setter
#NoArgsConstructor
#ToString
public class AircraftService {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private Integer minimumQuantity;
#NotNull
private Integer maximumQuantity;
#NotNull
private Integer defaultQuantity;
#NotNull
#ManyToOne(optional = false)
#JsonIgnore
private AircraftSeries aircraftSeries;
#NotNull
#Enumerated(EnumType.STRING)
private ServiceEnum serviceEnum;
}
If I comment out the #Table(uniqueConstraints = { #UniqueConstraint(columnNames = { "aircraft_series_id", "service_enum" }) }) annotation then the columns are created and I can see the field names when opening the table under the SQL client.
service_enum
aircraft_series_id
For now I'm running the application against the H2 database.
I could have the application running not throw an exception if the class is boasting the column annotations, as in:
#Column(name = "service_enum")
#ManyToOne(optional = false)
#JoinColumn(name = "service_profile_id")
I don't see why this is the case, as by default, the column names are exactly the same, when attributed by the application itself.

JPA NamedQuery with Join returning empty list

I've been struggling with a namedquery for a few days. The named query has an inner join to a 2nd table. One added complexity is that the primary key on the 2nd table is a composite key. I have the two tables simplified here:
Table: aname
nameIdx number(9),
firstName varchar2(40),
lastName varchar2(40),
primary key is nameIdx
Table: aname_role
nameIdx number(9), --foreign key to name table
nameType char(2),
inactiveFlag char(1)
composite primary key is on nameIdx and nameType
I am trying to emulate the following sql query in JPQL:
select * from aname n
left join aname_role nr on n.nameidx=nr.nameidx
where nr.nametype='5'
and nr.inactiveflag='N';
This query works as expected in Oracle returning many records. In Java I have these JPA entities:
#Entity
#Table(name="ANAME")
#NamedQueries({
#NamedQuery(name = "AName.findActiveSalesPersons", query = "SELECT a FROM AName a LEFT JOIN a.aNameRoleList r WHERE r.inactiveflag='N' and r.ANameRolePK.nametype='5' ")})
public class AName implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "NAMEIDX")
private Integer nameidx;
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "LASTNAME")
private String lastname;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "aName")
private List<ANameRole> aNameRoleList;
//getters and setters here
and
#Entity
#Table(name = "ANAME_ROLE")
public class ANameRole implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected ANameRolePK aNameRolePK;
#Basic(optional = false)
#NotNull
#Column(name = "INACTIVEFLAG")
private Character inactiveflag;
#JoinColumn(name = "NAMEIDX", referencedColumnName = "NAMEIDX", insertable = false, updatable = false)
#ManyToOne(optional = false)
private AName aName;
//getters and setters here
There is also a primary key class ANameRolePK
#Embeddable
public class ANameRolePK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "NAMEIDX")
private int nameidx;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 2)
#Column(name = "NAMETYPE")
private String nametype;
//getters and setters here
With this setup, including the named query specified in the AName entity above, the following returns an empty result list:
em.createNamedQuery("AName.findActiveSalesPersons").getResultList();
Can anyone point me to what I am doing wrong in this named query?
SELECT a FROM AName a LEFT JOIN a.aNameRoleList r WHERE r.inactiveflag='N' and r.aNameRolePK.nametype='5'
Thanks,
Steve
By default, at least using Hibernate, the default fetch type is Lazy, so you need to do a join fetch instead of a join. Also, you should have select distinct. Try:
SELECT distinct a FROM AName a LEFT JOIN fetch a.aNameRoleList r WHERE r.inactiveflag='N' and r.aNameRolePK.nametype='5'
References: Default fetch type for one-to-one, many-to-one and one-to-many in Hibernate
After more testing, I realized the join was working, but not the "r.aNameRolePK.nametype='5'". But if I changed that to "r.aNameRolePK.nameidx=1" it works. So, it was just the nametype field, which we have defined as a char(2) in the database. The problem is with the spaces in a char field and it is discussed here: Java NamedQuery String Problem. It looks like the recommended way to resolve this is to implement an EclipseLink SessionCustomizer. For testing I changed the named query to
SELECT a
FROM AName a LEFT JOIN a.aNameRoleList r
WHERE r.inactiveflag='N' and trim(trailing from r.aNameRolePK.nametype)=5
This returns the expected records.

JPA persist foreign key restriction violation

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;

JPA2/EclipseLink OneToMany cascade persist issue "Referential integrity constraint violation"

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.