Hibernate: detect linked field and save an object - java

How can I save object into database and simultaneously detect linked topic_id in the grammar.topics by topic_name?
public void updateResult(String topic_name, int userId) {
Session session = sessionFactory.getCurrentSession();
Beginner bgn = new Beginner();
bgn.setUserId(userId);
bgn.setScore(100);
// how to detect `topic_id` here by `topic_name` from the `grammar.topics`
bgn.setTopic_id( ... );
session.save(bgn);
}
#Entity
#Table(name = "beginner", uniqueConstraints =
{#UniqueConstraint(columnNames = {"user_id", "topic_id"})})
public class Beginner implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "user_id", nullable = false)
private int user_id;
#Id
#Column(name = "topic_id", nullable = false)
private int topic_id;
#Column(name = "score", nullable = false)
private int score;
//getters&setters

If in your method, you have not the id for Topic entity and you need it for persisting your Beginner entity, you must retrieve that information from the database.
If in Topic table , topic_name is UNIQUE. Easy : do a query where you retrieve the single Topic entity or the topicId with this topicName value. Ideally, you could avoid the query by keeping the topicId value when you retrieve the topic name information.
You could so replace topicName information in your processing by topicId information to be able to set the relation when you want to persist your Beginner instance. :
public void updateResult(String topicId, int userId)
instead of
public void updateResult(String topic_name, int userId)

Related

Jpa entity same record duplicated and making unique key violation

I am using Jpa, my website is shows a form in 3 steps, in every step i'm making save() in many steps :
First save() will create a record A with a primary key id and another unique key userId, data as firstname and lastname
Step 2 is where the user will enter his adress, then the same first save() is played
But I see an error :
ERROR: duplicate key value violates unique constraint "userId" XXXX already exists
A save() is supposed to make an update if the record exists, but I noted that my id increments in every save() how to prevent this incrementation ?
here is my entity :
#Table(name = "user", schema = "salesforce", uniqueConstraints = {
#UniqueConstraint(columnNames = { "userId" }) })
public class Beneficiary implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "userID")
private String userId;
#Column(name = "firstname")
private String firstname;
#Column(name = "lastname")
private String lastname;
The service :
void save(List<User> users, String idDocument); // it can be same users with same idDocument
public Beneficiary save(Beneficiary newBeneficiary);
The repository
#Override
public User save(User newUser) {
return userRepository.save(newUser);
}
#Override
#Transactional
public void save(List<User> users, String idDocument) {
users.forEach(newUser -> {
newUser.setDocument(new Document());
newUser.getDocument().setIDDocument(idDocument);
save(newUser);
});
}
In every step, the same save() is played but first i got the error saying that I'm trying to write a new ligne with the same UserId and it creates the duplication violation
This re-write is due to the fact that Id is incrementing ! why ?

How to allow duplicates in an arrayList when using JPA?

I keep getting "java.lang.IllegalStateException: Multiple representations of the same entity" even though I have the #Id set as true and I'm using a one to many relation on my variable.
Here are the classes which I'm trying to relate to one another:
#Entity
#Table(name = "map_area")
public class MapArea extends BasicModel {
#Id
#Column(nullable = false, unique = true)
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "area", referencedColumnName = "name")
public List<AlternativeAreaName> alternativeNames;
public MapArea() {}
public MapArea(String name) {
this.name = name;
this.alternativeNames = new ArrayList<>();
}
}
#Entity
#Table(name = "alternative_area_name")
public class AlternativeAreaName implements Serializable {
#Id
#Column(nullable = false, unique = false)
private String area;
#Column(nullable = true)
private String alternativeName;
public AlternativeAreaName(){}
public AlternativeAreaName(String area, String alternativeName) {
this.area = area;
this.alternativeName = alternativeName;
}
}
I want to have JPA create another table that relates to this one simple based on the name variable but whenever I try to add to the list and save to the DB I get
java.lang.IllegalStateException: Multiple representations of the same entity
MapArea mapArea = new MapArea("example");
AlternativeAreaName altAreaName1 = new AlternativeAreaName("example", "alt example");
AlternativeAreaName altAreaName2 = new AlternativeAreaName("example", "alt example2");
mapArea.alternativeNames.add(altAreaName2);
mapAreaRepository.save(mapArea);
You have used the private String area field as the primary key for entity AlternativeAreaName. So when you are trying to add
AlternativeAreaName altAreaName1 = new AlternativeAreaName("example", "alt example");
AlternativeAreaName altAreaName2 = new AlternativeAreaName("example", "alt example2");
Both of them have the same primary key. So it is throwing the above exception.
To generate the primary key for JPA entity, please check
https://www.objectdb.com/java/jpa/entity/id
https://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cmp30cfg001.htm

How to handle org.hibernate.ObjectNotFoundException

I am working on a Spring mvc app in which I am using Trip model and TripStop model. Trip model has list of trip stop models. Following is my Trip model:
#Entity
#Table(name = "Trip")
public class TripModel {
#Id
#Column(name = "tripid")
#GeneratedValue
private int tripId;
#Column(name = "tripname")
private String tripName;
#Column(name = "tripdesc")
private String tripDesc;
#Column(name = "createdate")
private Date createDate;
#OneToMany(mappedBy = "tripModel", fetch = FetchType.EAGER)
#Fetch(value = FetchMode.SUBSELECT)
private List<TripStopModel> tripStopList;
}
Following is my trip stop model:
#Entity
#Table(name="TripStop")
public class TripStopModel {
#Id
#Column(name="tripstopid")
#GeneratedValue
private int tripStopId;
#Column(name="datetime")
private String tripStopDateTime;
#Column(name="createts")
private Date tripStopCreateTime;
#ManyToOne(optional=true)
#JoinColumn(name="locationid")
private LocationModel locationModel;
public LocationModel getLocationModel() {
return locationModel;
}
public void setLocationModel(LocationModel locationModel) {
this.locationModel = locationModel;
}
#ManyToOne(optional=true)
#JoinColumn(name="userid")
private UserModel userModel;
#ManyToOne(optional=true)
#JoinColumn(name="tripid")
private TripModel tripModel;
}
This works fine. But when trip id is 0 in TripStop table, it shows following exception:
02:32:43,784 ERROR [stderr] (http--0.0.0.0-8080-5) org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.example.scm.model.TripModel#0]
Is there any option with which we can used trip id = 0 in TripStop table, without any exception? How can I allow this?
The tripID is defaulting to 0 because you are using primitives. Switch to primitive wrappers so these values can default to null and this should solve it

Hibernate QueryException

Hello I am trying to reference in a Criteria a property of a composite key which is defined as and #Embeddable on an Entity
#Entity
#Table(name = "B_J_P")
public class BJP implements java.io.Serializable {
private BJPId id;
private BJI bJI;
public BJP() {
}
public BJP(BJPId id, BJI bJI) {
this.id = id;
this.bJI = bJI;
}
#EmbeddedId
#AttributeOverrides( {
#AttributeOverride(name = "jIId", column = #Column(name = "J_I_ID", nullable = false)),
#AttributeOverride(name = "kN", column = #Column(name = "K_N", nullable = false, length = 100)),
public BJPId getId() {
return this.id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "J_I_ID", nullable = false, insertable = false, updatable = false)
public BJI getBJI() {
return this.bJI;
}
}
I need to reach the kName from the following:
#Embeddable
public class BJPId implements java.io.Serializable {
private long jIId;
private String kName;
public BJPId() {
}
public BJPId(long jIId, String kN) {
this.jIId = jIId;
this.kN = kN;
}
#Column(name = "J_I_ID", nullable = false)
public long getJIId() {
return this.jIId;
}
#Column(name = "K_NAME", nullable = false, length = 100)
public String getKName() {
return this.kName;
}
}
But when I am trying to reach it from the base class where BJP is a property with the following Criteria
DetachedCriteria timestampFilter = DetachedCriteria.forClass(BJP.class)
.createAlias("id","alias")
.add(Restrictions.eq("alias.kName","DataSetName"))
.setProjection(Projections.property("kName"));
I get the following error:
org.hibernate.QueryException: Criteria objects cannot be created directly on components. Create a criteria on owning entity and use a dotted property to access component property: id
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getPathInfo
How should I formulate the criteria query in order to reach the kName property to apply filtering based on it in a dynamic sql context ?
If I have not provided enough relevant information, please ask what have I forgotten to provide full context.
EDIT: Upon Genzetto advice I have managed to reach the elements(at least it is not giving errors now) but returns no results once I do this:
DetachedCriteria timestampFilter = DetachedCriteria.forClass(BJP.class)
.add(Restrictions.eq("id.kName","DataSetName"))
.setProjection(Projections.property("id.kName"));
Session currentSession = sessionFactory.getCurrentSession();
Criteria query = currentSession.createCriteria(BJI.class)
.add(Subqueries.propertyEq("bJP",timestampFilter))
as upon looking at the SQL it is of the format
... where this_.J_INST_ID = (select this_.K_NAME as y0_ from .B_J_P this_ where this_.K_NAME=?)
it is trying to add the subquery to the ID of the root object although I want it part of bJP. How can I add it to proper location ?
You don't need to use an alias to do this. You can access directly to the composite key attributes:
DetachedCriteria timestampFilter = DetachedCriteria.forClass(BJP.class)
.add(Restrictions.eq("id.kName","DataSetName"))
.setProjection(Projections.property("id.kName"));

Embeddable PK Object not populating after persist and flush

I have an embedded PK object that doesn't populate the id field after persisting and flushing to the database. The ID is an auto-increment field in the database.
Now normally, I would just try a refresh, but it throws the following error:
"Entity no longer exists in the database: entity.Customers[ customersPK=entity.CustomersPK[ id=0, classesId=36 ] ]."
public class Customers implements Serializable {
#EmbeddedId
protected CustomersPK customersPK;
...
}
#Embeddable
public class CustomersPK implements Serializable {
#Basic(optional = false)
#Column(name = "id")
private int id;
#Basic(optional = false)
#NotNull
#Column(name = "classes_id")
private int classesId;
.....
}
And here's the code that makes the call
Classes cl = em.find(Classes.class, classId);
CustomersPK custPK = new CustomersPK();
custPK.setClassesId(cl.getId());
Customers cust = new Customers(custPK);
em.persist(cust);
em.flush();
// The problem is right here where id always equals 0
int id = cust.getCustomerspk().getId();
Thanks for the help.
Why would the id not be 0, you have never set it?
If it is a generated id, you need to annotate it using #GeneratedValue, otherwise you need to set the value.

Categories

Resources