I am using Hibernate(3.0) + Oracle DB (10g) for my application.
My domain object are like PluginConfig.java
#Entity
#Table(name = "plugin_config" , schema = "test")
#org.hibernate.annotations.Cache(usage =org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
public class Config {
private static final long serialVersionUID = -1959019321092627830L;
/** This object's id */
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected long id;
#OneToOne
#JoinColumn(name = "plugin_id")
private Plugin plugin;
#Column(name = "config_name")
#NaturalId(mutable = true)
private String name;
#Column(name = "config_desc")
private String description;
another domain object Plugin.java
#Entity
#Table(name = "plugin", schema = "test")
#org.hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
public class Plugin implements Serializable {
private static final long serialVersionUID = 5694761325202724778L;
/** This object's id */
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected long id;
#Column(name = "plugin_name")
#NaturalId
private String pluginName;
#OneToOne
#JoinColumn(name = "plugin_config_id")
private PluginConfig pluginConfig;
#Column(name = "plugin_desc")
private String description;
Whenever i try to load Plugin via my database service method(using #Transactional annotation and hence it loads all its children as well) i get the following error
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [PluginConfig#53]
There is actually no row in plugin_config table with id = 53.
And also no plugin table entry has plugin_config_id=53.
So from where is hibernate picking these values ?
I noticed one thing here, the value "53" is actually the row number from the plugin_config table which should have been reffered.
See the below image:
This is the plugin config that my query should be looking for. But it tries to search it with identifier #53(Row no:) instead of the #95(value of the primary key "id").
Where can i be going wrong with this ?
I don't know if this is teh best solution, but you can use #NotFound annotation with IGNORE command to let Hibernate discard exception adn set pluginConfig to null.
#OneToOne
#JoinColumn(name = "plugin_config_id")
#NotFound(action = NotFoundAction.IGNORE)
private PluginConfig pluginConfig;
Related
I have a parent entity 'contracts' that has a one-to-one relation with another entity 'child-contract'. the interesting thing is that the mapping field ('contract_number')id not a primary key-foreign key but is rather a unique field in both the tables. Also it is possible for a contracts to not have any child contract altogether. With this configuration I have observed hibernate to generate 1 additional query every time a contracts does not have a child-contract. I filed this behavior very strange. Is there a way to stop these unnecessary query generation or have I got something wrong.
below is a piece of my code configuration.
#Data
#Entity
#Table(name = "contracts")
public class Contracts implements Serializable {
#Id
#JsonIgnore
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
#OneToOne(fetch=FetchType.EAGER)
#Fetch(FetchMode.JOIN)
#JsonProperty("crm_contracts")
#JoinColumn(name = "contract_number", referencedColumnName = "contract_number")
private ChildContract childContract ;
}
#Data
#NoArgsConstructor
#Entity
#Table(name = "child_contract")
#BatchSize(size=1000)
public class ChildContract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty("id")
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
}
Please help.
Thank-you
You can use NamedEntityGraph to solve multiple query problem.
#NamedEntityGraph(name = "graph.Contracts.CRMContracts", attributeNodes = {
#NamedAttributeNode(value = "crmContract") })
Use this on your repository method as
#EntityGraph(value = "graph.Contracts.CRMContracts", type = EntityGraphType.FETCH)
// Your repo method in repository
I have a table with two columns user_id and role_id. There's no unique column in table and I can't add one. How can I create Entity and Repository in Spring without a primary key?
This is my UserRole.class
public class UserRole {
#Column(name = "user_id")
private int userId;
#Column(name = "role_id")
private int roleId;
//getters and setters
}
But with this class i get the following error:
nested exception is org.hibernate.AnnotationException: No identifier specified for entity:
I saw that one of the answers is to use all of the columns as the id, but i have no idea how to do it.
Please see the awnser in this post. This should help you.
PK Explained
Another Option is if this is a join table, than you could make Embeded PK
#Embeddable
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder(toBuilder = true)
public class PersonGroupPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(insertable=false,unique = false, updatable=false, nullable=false)
private Long personId;
#Column(insertable=false, unique = false,updatable=false, nullable=false)
private Long groupId;
}
I'm having trouble with this #ManyToOne map, searched a lot, but still can't find a solution for this problem.
I have these two classes, i will never insert anything into TB_MANUAL, i'll just use it as reference for the CD_MANUAL field in TB_COMPANY, like this:
Company company = new Company();
company.setManual("2"); //Theres already a row with this id in the TB_MANUAL
and then persist company, but i got this error:
Caused By: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: 2.
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:313)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:723)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1516)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3168)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:355)
Truncated. see log file for complete stacktrace
-
#Entity
#Table(name = "TB_COMPANY", schema = "ADMPROD")
#Cacheable
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
public Company() {}
public Company(String id) {
this.id = id;
}
#ManyToOne
#JoinColumn(name = "CD_MANUAL", referencedColumnName = "CD_MANUAL", nullable
= true)
private Manual manual;
public void setManual(String idManual) {
this.manual = new Manual(idManual);
}
}
and
#Entity
#Table(name = "TB_MANUAL")
public class Manual implements Serializable{
private static final long serialVersionUID = 1L;
public Manual() {
}
public Manual(String id) {
this.id = id;
}
#Id
#Column(name = "CD_MANUAL")
private String id;
#Column(name = "DS_OBS_MANUAL")
private String description;
}
You create new Manual every time you set it, so your object is detach from EntityManager, or has not data at all.
I don't argue if that is a good design (althought I've never would do it like that), to over come your problem you should add CascadeType.PERSIST to your relation.
#ManyToOne
#JoinColumn(name = "CD_MANUAL", referencedColumnName = "CD_MANUAL", nullable
= true, cascade = CascadeType.PERSIST)
private Manual manual;
The problem was in the Manual table primary key, the JPA doesnt find any row with id 1 because the primary key of Manual is char(2), passing "1 " instead of "1" solved the problem.
I'm trying to learn Hibernate with this simple example but I'm having so trouble with the foreign key which remains "null" in the database.
#Entity
#Table(name = "tb1")
public class Track {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="id_tb1", unique= true)
private int id_tb1;
#Column(name = "title")
private String title;
#ManyToOne
#JoinColumn(name="id_tb2")
private tb2 cd;
And this is the second class
#Entity
#Table(name = "tb2")
public class CD {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="id_tb2", unique = true)
private int id_tb2;
#Column(name="title")
private String title;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,mappedBy = "cd")
private List<tb1> tracks = new ArrayList<tb1>();
I save like this:
SessionFactory factory = new Configuration().configure("/resources/hibernate.cfg.xml").buildSessionFactory();
Session session1 = factory.openSession();
session1.beginTransaction();
session1.save(tb2);
session1.getTransaction().commit();
but when Isavethe id_tb2 (in the table tb1) is not set and it remains null. What I'm missing?
The problem you have to set the relation on both sides for a bidirectional relationship.
So you have to set your relationship forCD and your Track object and persist/merge them afterwards.
Without seeing to much of your code you have to do something like.
cd.getTracks().add(track);
track.setCD(cd);
session1.save(track);
session1.save(cd);
See another question for more details.
I think your type of the table2
private tb2 cd;
should be changed as
private CD cd;
I have the following entity (getters and setters ommited)...
#Entity
#Table(name = "TBL_PROJECT_RUN")
public class ProjectRunEntity {
#Id
#Column(name = "ID")
#GeneratedValue(generator = "StakeholdersSequence")
#SequenceGenerator(name = "StakeholdersSequence", sequenceName = "STAKEHOLDERS_UPDATE_SEQ", allocationSize = 1)
private Integer id;
#Column(name = "REPORT_RUN_DATE")
private Date systemRunDate;
#Column(name = "JIRA_PROJECT_NAME")
private String jiraProjectName;
#Column(name = "JIRA_PROJECT_DESC")
private String jiraProjectDescription;
#Column(name = "RUNBY")
private String runBy;
#Column(name = "HEADER_TEXT")
private String headerText;
#Column(name = "FOOTER_TEXT")
private String footerText;
#Column(name = "JIRA_ID")
private String jiraId;
#Column(name = "TO_EMAIL")
private String toEmail;
#Column(name = "CC_EMAIL")
private String ccEmail;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "projectRunEntity")
private List<ProjectRunDetailsEntity> projectRunDetailsEntities;
Then I commit it to the database like this...
final Session session = sessionProvider.get();
session.persist(projectRunEntity);
session.flush();
return projectRunEntity.getId();
The id returned here is not what the actual id in the database is, it is 1 or 2 off. Please note I am sharing one sequence for all ids in all tables in my project so that any given entity has a project-wide unique index. What would cause the id to be incorrect like this?
It turns out that the web ui for oracle express automatically created triggers than insert an id from this sequence before inserting my row object. This meant that the generator in oracle was always 1 behind. To solve this I removed the triggers.
Two possibilities spring to mind:
You say you have a shared sequence. Are you inserting into other tables at the same time? (which could increment the sequence).
Is there a trigger on the database table which inserts a sequence value into the id column?