Im currently working with Hibernate and Java, im trying to persist objects in our database. We have a Group class and a ToDoList class. Group has a one-to-many relationship with ToDoList as show in this ERD.
The relevant code from the Group class:
#Entity
#Table(name = "Group", catalog = "db")
public class Group implements java.io.Serializable{
private int id;
private Set<ToDoList> allToDoLists;
public Group(){
allToDoLists = new HashSet<ToDoList>(0);
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "Group_id", unique = true, nullable = false)
public int getId(){
return this.id;
}
public void setId(int id){
this.id = id;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "group")
public Set<ToDoList> getAllToDoLists() {
return this.allToDoLists;
}
public void addTodoList(ToDoList t){
this.allToDoLists.add(t);
t.setGroup(this);
}
public void setAllToDoLists(Set<ToDoList> allToDoLists) {
this.allToDoLists = allToDoLists;
}
}
The relevant code from the ToDoList class:
#Entity
#Table (name = "Todo_List", catalog = "db")
public class ToDoList {
private int id;
private Group group;
public ToDoList(){}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "Todo_List_id", unique = true, nullable = false)
public int getId(){
return this.id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Group", nullable = false)
public Group getGroup() {
return this.group;
}
public void setGroup(Group group) {
this.group = group;
}
}
The code where the problem occurs:
ToDoList toDoList = new ToDoList("TodoList1","Iets","24-06-2015","24-06-2015");
Group group = new Group("Groep 1","10-11-2011","10-11-2011");
GroupDao groupDao = new GroupDaoImpl();
groupDao.store(group);
toDoList.setGroup(group);
toDoListDao.store(toDoList);
The code in 'groupDao' and 'toDoListDao' for storing are basicly the same:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(toDoList);
session.getTransaction().commit();
Problem
When I try to store the ToDoList I get the following error:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Group, Name) values ('2015-06-24', '2015-06-24', 'Iets', 23, 'TodoList1')' at line 1
Needed
It whould be best if I could store Group and ToDoList whould be save also.
Given our coming deadline it whould also suffice if I can store Group and ToDoList on their own
"Group" is an SQL keyword ("group by"). As such it is not the best choice of table name. It looks like this is causing conflicts given that Hibernate is generating SQL not accepted by the DBMS.
If you can't change the table name, you can probably solve that conflict by quoting the name in your entity, like so:
#Table(name = "`Group`", catalog = "db")
or
#Table(name = "\"Group\"", catalog = "db")
EDIT:
And as ug_ informs me, you can also set the following hibernate property in your persistence.xml file to do that by default to all identifiers:
<property name="hibernate.globally_quoted_identifiers" value="true" />
I have never used that myself, but the Javadocs confirm that this is indeed a supported property:
https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/cfg/AvailableSettings.html
Related
I'm trying to run a UT but is failing at the #Before method. This is the error:
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "UK_PBNJJ4MCIQ51S0SJV9U3J2WQ4_INDEX_5 ON PUBLIC.XACTIVITYCONTENTTYPE(CONTENTTYPE_ID) VALUES (19, 1)"; SQL statement:
insert into XACTIVITYCONTENTTYPE (ACTIVITY_ID, CONTENTTYPE_ID) values (?, ?) [23505-197]
I have an array of object(ActivityEntity) which I'm initializing and persisting in a H2 DB:
for (int i = 0; i < activities.length; i++) {
Date createdDate = new Date();
ActivityEntity activity = new ActivityEntity();
activity.setType(ActivityType.valueOf(properties.getType()));
activity.setLabel(ActivityLabel.valueOf(properties.getLabel()));
activity.setStatus(Status.valueOf(properties.getStatus()));
activity.setDeliveryType(DeliveryType.valueOf(properties.getDeliveryType()));
activity.setSubject(em.find(SubjectEntity.class, subjectId));
activity.setFontSize(FontSize.valueOf(properties.getFontSize()));
activity.setEstimatedTime(ESTIMATED_TIME);
activity.setPlannedTime(properties.getPlannedTime());
activity.setInteractivityType(InteractivityType.valueOf(properties.getInteractivityType()));
activity.setAudience(Audience.valueOf(properties.getAudience()));
activity.setPurpose(Purpose.valueOf(properties.getPurpose()));
activity.setAcademicLevel(AcademicLevel.valueOf(properties.getAcademicLevel()));
activity.setEnvironment(Environment.valueOf(properties.getEnvironment()));
activity.setInstructionMethod(InstructionMethod.valueOf(properties.getInstructionMethod()));
activity.setCreatedBy(CREATED_BY);
activity.setCreatedDate(createdDate);
activity.setModifiedBy(CREATED_BY);
activity.setModifiedDate(createdDate);
activity.setDeprecated(properties.isDeprecated());
activity.setTemplate(properties.isTemplate());
activity.setCurriculumProvider(CurriculumProvider.valueOf(properties.getCurriculumProvider()));
activity.setShowLessonNavigator(properties.isShowLessonNavigator());
activity.setShowHeader(properties.isShowHeader());
activity.setDisplayModuleType(properties.isDisplayModuleType());
activity.setDisplayLabelType(properties.isDisplayLabelType());
activity.setShowFooter(properties.isShowFooter());
activity.setShowPagination(properties.isShowPagination());
activity.setDisplayProgressBar(properties.isDisplayProgressBar());
activity.setDisplayResources(properties.isDisplayResources());
activity.setLanguage(language);
activity.setPrimaryStatus(PrimaryStatus.valueOf(properties.getPrimaryStatus()));
activity.setIntendedDeliveryType(IntendedDeliveryType.valueOf(properties.getIntendedDeliveryType()));
activity.setNextGen(properties.isNextGen());
activity.setExcludeFromSearch(properties.isExcludeFromSearch());
activity.setExcludeFromRecommender(properties.isExcludeFromRecommender());
activity.setTeacherCreated(properties.isTeacherCreated());
activity.setTitle(TITLE + (i + 1), language);
activity.getGrades().addAll(grades);
activity.getStudentGroupings().add(new StudentGroupingEntity(properties.getStudentGroupingId()));
activity.getPedagogicalIntents().add(new PedagogicalIntentEntity(properties.getPedagogicalIntentId()));
activity.getLearnerTypes().add(new LearnerTypeEntity(properties.getLearnerTypeId()));
activity.getContentTypes().add(new ContentTypeEntity(properties.getContentTypeId()));
activities[i] = em.persist(activity);
}
em.flush();
The last set it's the property related to the error. The properties have a value of 19 for the ContentTypeId. Now, this is part of the Activity entity class:
#Entity
#Table(name = "ACTIVITY")
public class ActivityEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_ACTIVITY_ACTIVITY_ID")
#SequenceGenerator(name = "SQ_ACTIVITY_ACTIVITY_ID", sequenceName = "SQ_ACTIVITY_ACTIVITY_ID", allocationSize = 1)
#Column(name = "ACTIVITY_ID")
private Integer id;
//MORE FIELDS LEFT OUT FOR CLARITY
#ManyToMany
#JoinTable(name = "XACTIVITYCONTENTTYPE", joinColumns = { #JoinColumn(name = "ACTIVITY_ID", referencedColumnName = "ACTIVITY_ID") }, inverseJoinColumns = { #JoinColumn(name = "CONTENTTYPE_ID", referencedColumnName="ID") } )
private List<ContentTypeEntity> contentTypes = new ArrayList<>();
}
And here's the ContentTypeEntity class:
#Entity
#Table(name = "CONTENTTYPE")
public class ContentTypeEntity {
#Id
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#Column(name = "SEQ_NUM")
private int seqNum;
public ContentTypeEntity() {
}
public ContentTypeEntity(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSeqNum() {
return seqNum;
}
public void setSeqNum(int seqNum) {
this.seqNum = seqNum;
}
}
If I debug, the ids for ActivityEntity is being generated correctly for each of the 3 objects that i'm putting in the array (ids=[1,2,3]). So i don't understand why the second insert is using the id=1, which is what the exception is implying. If I put one ActivityEntity in the array, everything works correctly.
You haven't pasted in all the code and you cannot assign the return type of em.persist, but i think the issue is probably related to creating multiple instances of contenttype with id 19.
Assuming content type with id 19 is already persisted and you are attempting to just create references to it rather than persist it as you have no cascade in your ManyToMany you can do something like this as this sample test code shows. The transaction are there as I don't know your tx boundaries in your code and just for the purpose of saving the contenttype separately
#Test
public void saveActivities() {
// Tx1 - Persist content type
EntityTransaction tx1 = em.getTransaction();
tx1.begin();
ContentTypeEntity contentType = new ContentTypeEntity(19);
em.persist(new ContentTypeEntity(19));
tx1.commit();
em.detach(contentType);
// Tx2 - Persist activities using a reference to content type
EntityTransaction tx2 = em.getTransaction();
tx2.begin();
for (int i = 0; i < 3; i++) {
ActivityEntity activity = new ActivityEntity();
activity.getContentTypes().add(em.getReference(ContentTypeEntity.class, 19));
em.persist(activity);
}
tx2.commit();
// assertions
}
I have two models: Ordine and DettaglioOrdine.
I would like that, when I save an object of type "Ordine", hibernate also save his child "DettaglioOrdine" (and this works).
But, if I do a select query, the query is very very slow because hibernate retrieve also DettaglioOrdine. So, I would like the "Ordine" object without "DettaglioOrdine" object.
"Ordine" model:
#Entity
#Table(name="ordini")
#NamedQuery(name="Ordine.findAll", query="SELECT o FROM Ordine o")
public class Ordine extends DataObject<Integer> {
private static final long serialVersionUID = 1L;
private Integer id;
[...]
private List<Dettagliordine> dettagliordine;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
//bi-directional many-to-one association to Dettagliordine
#Column(insertable = true, updatable = true)
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="ordine")
public List<Dettagliordine> getDettagliordine() {
return this.dettagliordine;
}
public void setDettagliordine(List<Dettagliordine> dettagliordine) {
this.dettagliordine = dettagliordine;
}
public Dettagliordine addDettagliordine(Dettagliordine dettaglioordine) {
dettaglioordine.setOrdine(this);
this.dettagliordine.add(dettaglioordine);
return dettaglioordine;
}
public Dettagliordine removeDettagliordine(Dettagliordine dettagliordine) {
dettagliordine.setOrdine(null);
this.dettagliordine.remove(dettagliordine);
return dettagliordine;
}
}
DettaglioOrdine Model:
#Entity
#Table(name="dettagliordine")
#NamedQuery(name="Dettagliordine.findAll", query="SELECT d FROM Dettagliordine d")
public class Dettagliordine extends DataObject<Integer> {
private static final long serialVersionUID = 1L;
private Integer id;
[...]
public Dettagliordine() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
[...]
//bi-directional many-to-one association to Ordini
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="idOrdine", nullable=false)
public Ordine getOrdine() {
return this.ordine;
}
public void setOrdine(Ordine ordine) {
this.ordine = ordine;
}
}
And this is my query:
SessionFactory sessionFactory = getSessionFactory();
Session session = sessionFactory.getCurrentSession();
List<OrdineDTO> result = null;
try{
String hql = "select d.ordine from Dettagliordine d "
+ "group by d.ordine.id";
Query<Ordine> query = session.createQuery(hql,Ordine.class);
List<Ordine> res = query.getResultList();
result = new OrdineDMO().unmarshall(res);
}catch (DMOException e) {
e.printStackTrace();
}
It is not Hibernate. You have fetch=FetchType.LAZY for dettagliordine. Hibernate doesn't have to fetch the lazy association with the parent.
The problem can be here
result = new OrdineDMO().unmarshall(res);
if the code inside unmarshall() method touches dettagliordine or invoke a method, that differs from get, set methods (like toString() method), Hibernate will fetch dettagliordine association.
You can enable Hibernate logging and debug the code. You will see when fetching actually happens. Also keep in mind, if you debug persistent classes, the debugger can cause invoking of toString() method and the association will be fetched too.
Better to move this line outside session/#Transactional block of code.
result = new OrdineDMO().unmarshall(res);
You will have LazyInitializationExcepton, with any unwanted access to lazy associations.
I am using envers in my project to audit data.
Now I want to access changed data with audit query.
My pojo class for table is below
#Entity
#Audited(withModifiedFlag=true)
#Table(name = "INSTRUMENT", uniqueConstraints = #UniqueConstraint(columnNames = "INSTRUMENT_NAME"))
public class Instrument implements java.io.Serializable {
private long instrumentId;
private String instrumentName;
private WorkflowState workflowState;
#Id
#Column(name = "INSTRUMENT_ID", unique = true, nullable = false, precision = 22, scale = 0)
public long getInstrumentId() {
return this.instrumentId;
}
public void setInstrumentId(long instrumentId) {
this.instrumentId = instrumentId;
}
#Column(name = "INSTRUMENT_NAME", unique = true, nullable = false, length = 50)
public String getInstrumentName() {
return this.instrumentName;
}
public void setInstrumentName(String instrumentName) {
this.instrumentName = instrumentName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS", nullable = false)
public WorkflowState getWorkflowState() {
return this.workflowState;
}
public void setWorkflowState(WorkflowState workflowState) {
this.workflowState = workflowState;
}
}
Now I tried to access this with audit query as
AuditQuery query = reader.createQuery().forRevisionsOfEntity(Instrument.class, false, true)
.add(AuditEntity.property("status").hasChanged());
List list= query.getResultList();
So at the time of accessing getResultList() , Its throwing Exception as follows
SqlExceptionHelper: Fail to convert to internal representation
I figured it out, this is because in my db Instrument.status column is as String data Type. While here I am using Join.
So please tell me how to write query to resolve this problem
PROBLEM is How to write Audit Query if my table has foreign key (class property have join dependency).
Join table WorkflowState discription is as follows
public class WorkflowState implements java.io.Serializable {
private BigDecimal stateId;
private Workflow workflow;
private String stateName;
//getters and setters
And it has a join column too i.e "workflow" .
Use workflowState rather than status. The API is based on you specifying the property name and not the column name.
My scenario is very simple. I have an entityID identity field in the #Entity class and the DB (Oracle, which I'm not sure that matters):
#Id
#SequenceGenerator(name="ENTITY_SEQ_GEN", sequenceName="SEQ_GENERIC", allocationSize = 1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ENTITY_SEQ_GEN")
#Column(name="ENTITY_ID")
private long entityID;
I have another field called, let's say, entityReadableID and that should be a String consisting of the stringified entityID concatenated with another String field from the entity. E.g. if entityID is 1234, entityReadableID may be something like 1234ABC.
My problem is that, as far as I know, the value of entityID is not known before the row is created in the DB but I need to concatenate the entityReadableID using its value. Is there a way to fetch the value of the sequence generated ID before the row is created in the DB so that I can use it to generate the other ID? I know I can make it an insert with that field being null and then make an update once I know what entityID is but that solution seems less than elegant.
The way I am hoping Hibernate/Oracle may be able to support this is if Hibernate can somehow "reserve/issue" the next generated value for the entity being processed before the actual persistence, let me know what it is so I can manipulate with it, then at the end persist it.
You can get the generated Id before persisting of that entity by not using sequence directly for that entity, I mean use a separated entity for that sequence, so your entity should be something like:
#Entity
#Table(name = "ENTITY"
)
public class EntityClass implements java.io.Serializable {
private Long entityId;
private String entityRelatedId;
public EntityClass() {
}
// you may have other constructors
#Id
#Column(name = "ENTITY_ID", nullable = false)
public Long getEntityId() {
return this.entityId;
}
public void setEntityId(Long entityId) {
this.entityId = entityId;
}
#Column(name = "ENTITY_RELATED_ID", length = 50)
public String getEntityRelatedId() {
return this.entityRelatedId;
}
public void setEntityRelatedId(String entityRelatedId) {
this.entityRelatedId = entityRelatedId;
}
}
and the entity for the sequence is something like:
#Entity
#Table(name = "SEQ_GENERIC_TBL"
)
public class SeqGenericTbl implements java.io.Serializable {
private Long id;
public SeqGenericTbl() {
}
public SeqGenericTbl(Long id) {
this.id = id;
}
#Id
#SequenceGenerator(name = "ENTITY_SEQ_GEN",
sequenceName = "SEQ_GENERIC", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ENTITY_SEQ_GEN")
#Column(name = "ID")
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
}
Now you can get the Id from the entity of the sequence (persist it, you can rollback that tran or delete it or empty the related table later):
SessionFactory sf = HBUtil.getSessionFactory();
Session s = sf.openSession();
SeqGenericTbl sg=new SeqGenericTbl();
s.save(sg);
EntityClass entity1 = new EntityClass();
entity1.setEntityId(sg.getId());
//NOW YOU HAVE THE ID WITHOUT PERSISTING THE ENTITY
System.out.println(entity1.getEntityId());
Having a bit of bother trying to figure out how to get my #ManyToMany mapping working in Hibernate in Dropwizard (using dropwizard-hibernate 6.2). I've tried several of the online examples. I'm trying to persist a twitter stream with user_mentions saved in a Targets table which is m2m with the Tweets table. So far all my attempts have been with an existing Target and a new Tweet (and due to my business rules, that will always be the case). I'll show code momentarily, but the consistent problem I'm having is that that the tweets_targets table winds up in all cases with the target_id set to the correct value, but the tweet_id set to 0.
Code is based on an article here: http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/
// Target class
#Entity
#Table(name="targets")
public class Target {
private long id;
private List<Tweet> tweets = new ArrayList<Tweet>();
#Id
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#ManyToMany(mappedBy="targets",targetEntity=Tweet.class)
public List<Tweet> getTweets() {
return tweets;
}
public void setTweets(List<Tweet> tweets) {
this.tweets = tweets;
}
}
// Tweet class
#Entity
#Table(name="tweets")
public class Tweet {
private long id;
private List<Target> targets = new ArrayList<Target>();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "targets_tweets", joinColumns = {
#JoinColumn(name = "tweet_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "target_id", nullable = false, updatable = false)
})
public List<Target> getTargets() {
return this.targets;
}
public void setTargets(List<Target> targets) {
this.targets = targets;
for(Target t: targets){
t.getTweets().add(this);
}
}
}
The actual saving of a new Tweet is done in the DAO class which inherits from AbstractDAO in DropWizard. Relevant code is:
public long create(Tweet tweet) {
tweet.setTargets(getTargets(tweet));
return persist(tweet).getId();
}
#SuppressWarnings("unchecked")
private List<Target> getTargets(Tweet tweet) {
String[] mentions = tweet.getUserMentions().split(",");
return namedQuery(Target.FIND_BY_HANDLE)
.setParameterList("handles", mentions).list();
}
My named query just returns a list of all my targets based on their twitter handle as reported by the streams API.
Found the answer, hopefully this will help someone else.
The Id's in my DB are autoincrementing (I know, there's all kinds of debate on that, but it's what I have to work with), so once I added the annotation #GeneratedValue(strategy=GenerationType.IDENTITY) to the Tweet's Id property, everything started working.