- This topic has 13 replies, 4 voices, and was last updated 12 years, 10 months ago by Satwa S. Rao.
-
AuthorPosts
-
Glenn PuckettParticipantI have been struggling for a couple of weeks now with my generated code and foreign keys. I hope someone can provide some suggestions as to how to get past this. I suppose my alternative is to code this outside of the Spring annotations. But that just doesn’t seem to be the right way to go about this.
After beating my head against the wall trying to scaffold a fairly complex set of tables I decided I would set up a simple test just to see what I might be doing wrong. So I tried a different route. Set up two tables with one foreign key linking the two. One table is called account. The other table is called person. Both tables have an automatic incrementing integer as the primary key.
I am using MySQL v5.5. I have MyEclipse for Spring v8.6.
My two tables are defined as:
CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `owner` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name_UNIQUE` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `person` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `location` varchar(45) NOT NULL, `account_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `FK_PERSON_ACCOUNT` (`account_id`), CONSTRAINT `FK_PERSON_ACCOUNT` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
So the relationship is One-To-Many with one account to many persons.
On MyEcipse I added a Web Project and called it CRUD.
Then I selected the Scaffold Spring CRUD application and made the following selections:
> Artifact Type Database Schema
> Select Databse Connection MySQL
> Select Database Tables Added account and person
> Database Scaffolding OPtions Selected account table as parent
> Application Layers and Packages mm.crud
> Web Client Spring MVC
> Customize User Interface I deselected the id fields as they are automatic incrementHere I clicked “Finish” and accepted the remaining defaults.
The resulting code has a number of errors. Both java modules in the domain package have errors. Here is the code generated for the Account table. I have cleaned it up a bit so it wouldn’t take so many lines.
package mm.crud.domain; @Entity @NamedQueries( {@NamedQuery(name = "findAccountById", query = "select myAccount from Account myAccount where myAccount.id = ?1"), @NamedQuery(name = "findAccountByName", query = "select myAccount from Account myAccount where myAccount.name = ?1"), @NamedQuery(name = "findAccountByNameContaining", query = "select myAccount from Account myAccount where myAccount.name like ?1"), @NamedQuery(name = "findAccountByOwner", query = "select myAccount from Account myAccount where myAccount.owner = ?1"), @NamedQuery(name = "findAccountByOwnerContaining", query = "select myAccount from Account myAccount where myAccount.owner like ?1"), @NamedQuery(name = "findAccountByPrimaryKey", query = "select myAccount from Account myAccount where myAccount.id = ?1"), @NamedQuery(name = "findAllAccounts", query = "select myAccount from Account myAccount") }) @Table(catalog = "crud", name = "account") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace = "CRUD Test/mm/crud/domain", name = "Account") @XmlRootElement(namespace = "CRUD Test/mm/crud/domain") public class Account implements Serializable { private static final long serialVersionUID = 1L; @Column(name = "id") @Basic(fetch = FetchType.EAGER) @Id @XmlElement Integer id; @Column(name = "name") @Basic(fetch = FetchType.EAGER) @XmlElement String name; @Column(name = "owner") @Basic(fetch = FetchType.EAGER) @XmlElement String owner; @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE }, fetch = FetchType.LAZY) @XmlElement(name="", namespace="") persons; >>>>>>>>> ERROR 1 <<<<<<<<<<<<< public void setId(Integer id) { this.id = id; } public Integer getId() { return this.id; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void setOwner(String owner) { this.owner = owner; } public String getOwner() { return this.owner; } public void setPersons( persons) { >>>>>>>>>> ERROR 2 <<<<<<<<<< this.persons = persons; } public getPersons() { >>>>>>>>>> ERROR 3 <<<<<<<<<< if (persons == null){ >>>>>>>>>> ERROR 4 <<<<<<<<<< persons = ; >>>>>>>>>> ERROR 5 <<<<<<<<<< } return persons; >>>>>>>>>> Error 6 <<<<<<<<<< } public Account() { } /** * Copies the contents of the specified bean into this bean. * */ public void copy(Account that) { setId(that.getId()); setName(that.getName()); setOwner(that.getOwner()); setPersons (new (that.getPersons())); } @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("id=[").append(id).append("] "); buffer.append("name=[").append(name).append("] "); buffer.append("owner=[").append(owner).append("] "); return buffer.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result + ((id == null) ? 0 : id.hashCode())); return result; } @Override public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof Account)) return false; Account equalCheck = (Account) obj; if ((id == null && equalCheck.id != null) || (id != null && equalCheck.id == null)) return false; if (id != null && !id.equals(equalCheck.id)) return false; return true; } }
Notice the six errors. The errors are:
1. Syntax error on token “persons”, VariableDeclarator expected after this token
2. persons cannot be resolved to a type
3. Return type for the method is missing
4. persons cannot be resolved
5. Syntax error on token “=”, Expression expected after this token
6. persons cannot be resolved to a typeThe person domain object was equally screwed up.
The service and web code had many errors. Mostly with missing instances of or references to the person and account classes.
What did I do wrong? I have searched all weekend for references to problems with MyEclipse for Spring and foreign keys and found nothing. So I am assuming I did something wrong. I am beginning to get desparate!!!!!
jkennedyMemberI am sorry for the delay in responding, I have been trying to reproduce this error and I am afraid that I can not.
Can you look in the Errors view after scaffolding to see if there are any hints as to what may be going wrong during the generation?
Please rerun the scaffolding and export the Error log and send it in response.
You can also email me directly at jkennedy@skywaysoftware.com.
Can you also tell me which version of the driver you are using as well as your database and connection details.
1. Driver and version
2. Connect String
3. User Name
4. Database nameThanks,
Jack
Glenn PuckettParticipantI will do so shortly.
What I have found is the scaffolding is incapable of reverse engineering tables with foreign keys. I am slowly getting it to work by removing the foreign keys, reverse engineering the Spring, adding the foreign keys back and then manually adding the support for the foreign keys to the generated code. Needless to say this took ages to figure out and has been a big hastle getting it working. But it is helping me to learn how it all fits together. That is a good thing if I only had the time to blow doing this. And I am not convinced that the way I was able to determine how to implement the support of the foreign keys is very efficient. But I also don’t know if there are other alternatives. I had little knowledge of Hibernate or JPA at the start of this exercise.
jkennedyMemberThe software is definitely able to reverse engineer tables with foreign keys. I actually was able to generate an application using the exact DDL that you posted within MyEclipse for Spring pointing at MySQL without issue.
I believe this issue will wind up being either a slight variance in the way that the database meta data is being returned by the driver, or the specifics of the connection and the user and its access to the metadata etc.
Hopefully if you can get me the details we can discover the root cause and get you on your way to utilizing the tool to handle your data model.
Btw, here is the Account entity as it was generated in ME4S against your DDL.
package com.xxx.test.domain; import java.io.Serializable; import java.lang.StringBuilder; import java.util.LinkedHashSet; import java.util.Set; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.xml.bind.annotation.*; import javax.persistence.*; /** */ @Entity @NamedQueries( { @NamedQuery(name = "findAccountById", query = "select myAccount from Account myAccount where myAccount.id = ?1"), @NamedQuery(name = "findAccountByName", query = "select myAccount from Account myAccount where myAccount.name = ?1"), @NamedQuery(name = "findAccountByNameContaining", query = "select myAccount from Account myAccount where myAccount.name like ?1"), @NamedQuery(name = "findAccountByOwner", query = "select myAccount from Account myAccount where myAccount.owner = ?1"), @NamedQuery(name = "findAccountByOwnerContaining", query = "select myAccount from Account myAccount where myAccount.owner like ?1"), @NamedQuery(name = "findAccountByPrimaryKey", query = "select myAccount from Account myAccount where myAccount.id = ?1"), @NamedQuery(name = "findAllAccounts", query = "select myAccount from Account myAccount") }) @Table(catalog = "jkennedy", name = "account") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace = "ForumTester/com/xxx/test/domain", name = "Account") @XmlRootElement(namespace = "ForumTester/com/xxx/test/domain") public class Account implements Serializable { private static final long serialVersionUID = 1L; /** */ @Column(name = "id", nullable = false) @Basic(fetch = FetchType.EAGER) @Id @XmlElement Integer id; /** */ @Column(name = "name", length = 45, nullable = false) @Basic(fetch = FetchType.EAGER) @XmlElement String name; /** */ @Column(name = "owner", length = 45) @Basic(fetch = FetchType.EAGER) @XmlElement String owner; /** */ @OneToMany(mappedBy = "account", cascade = { CascadeType.REMOVE }, fetch = FetchType.LAZY) @XmlElement(name = "", namespace = "") java.util.Set<com.xxx.test.domain.Person> persons; /** */ public void setId(Integer id) { this.id = id; } /** */ public Integer getId() { return this.id; } /** */ public void setName(String name) { this.name = name; } /** */ public String getName() { return this.name; } /** */ public void setOwner(String owner) { this.owner = owner; } /** */ public String getOwner() { return this.owner; } /** */ public void setPersons(Set<Person> persons) { this.persons = persons; } /** */ public Set<Person> getPersons() { if (persons == null) { persons = new java.util.LinkedHashSet<com.xxx.test.domain.Person>(); } return persons; } /** */ public Account() { } /** * Copies the contents of the specified bean into this bean. * */ public void copy(Account that) { setId(that.getId()); setName(that.getName()); setOwner(that.getOwner()); setPersons(new java.util.LinkedHashSet<com.xxx.test.domain.Person>(that.getPersons())); } /** * Returns a textual representation of a bean. * */ public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("id=[").append(id).append("] "); buffer.append("name=[").append(name).append("] "); buffer.append("owner=[").append(owner).append("] "); return buffer.toString(); } /** */ @Override public int hashCode() { final int prime = 31; int result = 1; result = (int) (prime * result + ((id == null) ? 0 : id.hashCode())); return result; } /** */ public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof Account)) return false; Account equalCheck = (Account) obj; if ((id == null && equalCheck.id != null) || (id != null && equalCheck.id == null)) return false; if (id != null && !id.equals(equalCheck.id)) return false; return true; } }
Thanks,
Jack
rcampbeMemberI am also trying to get a parent child scaffolding to work. The code you posted looks like mine. But is the scaffolding supposed to generate the jsp for the relationship? I used Spring MVC. My jsp files don’t have any way to associate the two. In your example what should the jsp for editing Account look like? How do you edit the Persons on the Account? Thanks for the good info so far.
jkennedyMemberAs long as the scaffolding engine is able to get the JDBC meta data that tells it about the relationships, it will generate code to manage the objects and their relationships at every level, including the Entity, DAO, Service and UI layers.
One thing that may not be completely obvious is that the controls to manage the relationships are on the “view” screen for an Entity, not the Edit Screen for the entity (by default).
And so if you run your application, and then create a parent object, and then click the “view” icon in the list, you should see a page that shows you the details of the parent, and a list of the children, with a button that lets you add a new child.
The code for the vewAccount.jsp page looks like this:
<%@page language="java" isELIgnored="false" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <jsp:directive.include file="/WEB-INF/sitemesh-decorators/include.jsp"/> <fmt:setBundle basename="bundles.account-resources"/> <html> <head> <title>View <fmt:message key="account.title"/></title> </head> <body> <div id="contentarea"> <div id="lb"><div id="rb"><div id="bb"><div id="blc"> <div id="brc"><div id="tb"><div id="tlc"><div id="trc"> <div id="content"> <h1><fmt:message key="account.title"/> Details</h1> <div class="navitem"><a class="button" href="${pageContext.request.contextPath}/indexAccount"><span><img src="images/icons/back.gif" /><fmt:message key="navigation.back"/></span></a></div> <table cellpadding="0" cellspacing="0" id="viewTable"> <tbody> <tr> <td class="label" valign="top"> <fmt:message key="account.id.title"/>: </td> <td> ${account.id} </td> </tr> <tr> <td class="label" valign="top"> <fmt:message key="account.name.title"/>: </td> <td> ${account.name} </td> </tr> <tr> <td class="label" valign="top"> <fmt:message key="account.owner.title"/>: </td> <td> ${account.owner} </td> </tr> </tbody> </table> <div class="clear"> </div> <div class="spacer"> </div> <h1><fmt:message key="person.title"/></h1> <div class="navitem"><a class="button" href="${pageContext.request.contextPath}/newAccountPersons?account_id=${account.id}&"><span><img src="${pageContext.request.contextPath}/images/icons/new.gif" /><fmt:message key="navigation.new"/> <fmt:message key="person.title"/></span></a></div> <table cellpadding="0" cellspacing="0" id="viewTable"> <thead> <tr> <th class="thead"> </th> <th class="thead"><fmt:message key="person.id.title"/></th> <th class="thead"><fmt:message key="person.name.title"/></th> <th class="thead"><fmt:message key="person.location.title"/></th> </tr> </thead> <tbody> <c:forEach items="${account.persons}" var="current" varStatus="i"> <c:choose> <c:when test="${(i.count) % 2 == 0}"> <c:set var="rowclass" value="rowtwo"/> </c:when> <c:otherwise> <c:set var="rowclass" value="rowone"/> </c:otherwise> </c:choose> <tr class="${rowclass}"> <td nowrap="nowrap"> <a title="<fmt:message key="navigation.view" />" href="${pageContext.request.contextPath}/selectAccountPersons?account_id=${account.id}&persons_id=${current.id}&"><img src="images/icons/view.gif" /></a> <a title="<fmt:message key="navigation.edit" />" href="${pageContext.request.contextPath}/editAccountPersons?account_id=${account.id}&persons_id=${current.id}&"><img src="images/icons/edit.gif" /></a> <a title="<fmt:message key="navigation.delete" />" href="${pageContext.request.contextPath}/confirmDeleteAccountPersons?account_id=${account.id}&persons_id=${current.id}&"><img src="images/icons/delete.gif" /></a> </td> <td> ${current.id} </td> <td> ${current.name} </td> <td> ${current.location} </td> </tr> </c:forEach> </tbody> </table> <div class="clear"> </div> </div> </div></div></div></div> </div></div></div></div> </div> </body> </html>
rcampbeMemberThank you. Mine looks the same. I feel like it’s very close to working however I got an exception trying to add a new child.
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: aa.bb.cc.Divoverheadcategories.divcategorygroupswhere Divoverheadcategories is the child and divcategorygroups is the parent.
Viewing the source of the jsp page in a browser has the following line near the save button which tells me it knows what Group (parent) this new Category should be associated with.<input type=”hidden” name=”divcategorygroups_divCatGroupId” value=”3″ >
Any ideas?
rcampbeMemberGot it to work with several database mods. Created a combined or composite key on the child table including the Id of the parent and a name column. This is similar to the CLASSICCARS db; Customer, Payment example. However, this won’t work for me because the Name on my child table must be a user editable piece of data. Need a DB design that has the same result. Other scaffolding attempts with a db generated primary key and a single column foreign key to the parent table Id didn’t seem to work. Appreciate any input.
jkennedyMemberCan you post the DDL for your table structure and I will give it a try. (The table structure that you want but that doesn’t seem to work). I believe the error that you mentioned above has to do with have a relationship that is not nullable but I would like to verify that. In this case, it is likely that you are trying to persist a parent object where the related objects is set as being “not nullable” and the persistence layer is throwing this exception.
You should be able to use a generated key, I will look for your DDL.
Thanks,
Jack
Glenn PuckettParticipantAfter a great deal of pain and agony I have decided to forgo my plans of using Spring at this point. I could never get anything to work beyond what was generated by the scaffolding. It was just taking far too long to get Spring code to work. I would have to spend days researching each little issue. Things that would seem to work in a tutorial I could never get to work in different code. I have decided to go back to Struts 2, EJB 3 and Hibernate for my project.
I think you were correct about the meta data aspect of the reverse engineering. I discovered that if I created the tables using the MySQL Workbench the meta data was different than if I generated the tables using my own DDL. So I created an SQL file with the table creates in them and was able to get the reverse engineering to work without syntax error. However, I am still having problems with understanding what is happening. But I think this is a Hibernate/JPA issue. I will go to that forum with my questions.
I think Spring is one of those technologies that a formal class is called for to jump start a person’s ability to implement it properly. Or a lot of time spent building up knowledge in small increments.
I appreciate your help in this.
jkennedyMemberI’m sorry to hear that you were not able to make the leap to Spring in this case. A big part of our goal in generating Spring applications is to help developers who are new to Spring to get an application up and running using best practices etc, in as little time as possible. Generally speaking, the Spring Framework is well documented and well supported by a strong community. As is true with all frameworks (struts and hibernate included) there is an initial investment in getting proficient, but usually the investment is worth the time. In this case, it sounds like some of the learning curve may have also been in the JPA layer which is independent of Spring. Thanks for working with the Scaffolding capabilities of MyEclipse. Let me know if there is anything else that we can do to assist you.
Jack
Glenn PuckettParticipantThe best feedback I can think of is better tutorials on all of the functions. When I first started using MyEclipse I didn’t need to go further than the tutorials and other educational materials available on the site. But it appears you have been spending all your resources on new product and documentation and educational materials have fallen off the list.
You don’t even have a tutorial on how to use the Struts 2 capabilities of MyEclipse. Sure, I can and have gone to other resources for that but there are no tutorials out there that describe how to use the Struts 2 graphical interface. At least none that I can find. The few sites I find tutorials make it impossible to get through because they are more interested in their commercial ads than the tutorial itself.
I had a lot of questions about how to make Spring work. Even though there is a lot of information out there it pretty much all says the same thing. If you have a question otherwise nobody bothers to answer in the forums. The most significant problem I ran into that was the final straw was with all the introspection and injection it is pretty much impossible to locate the actual point of failure when code breaks. Because it is hidden inside all the control classes. Maybe there is a way to manage that. But I don’t have the time to find out.
I do appreciate your assistance. I like the MyEclipse platform. It just didn’t work for me in this situation.
rcampbeMemberAttempting a many-to-many with a intermediate table or link table. This is MS SQLServer. It may be something I need to manually edit after generating but these 3 tables hopefully gives you the idea. This allows several categories to be in a group. It also allows a category to be “used again” and be in more than one group. Thanks.
CREATE TABLE [Groups](
[group_id] [int] IDENTITY(1,1) NOT NULL,
[group_name] [varchar](50) NOT NULL,
[sort_num] [int] NOT NULL,
CONSTRAINT [PK_DivCategoryGroups] PRIMARY KEY CLUSTERED
(
[group_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]CREATE TABLE [Categories](
[category_id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[sort_num] [int] NOT NULL,
CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED
([category_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]CREATE TABLE [CategoryGroups](
[category_group_id] [int] IDENTITY(1,1) NOT NULL,
[group_id] [int] NOT NULL,
[category_id] [int] NOT NULL,
CONSTRAINT [PK_DivCategory_RC_1] PRIMARY KEY CLUSTERED
([category_group_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]GO
ALTER TABLE [CategoryGroups] WITH CHECK ADD CONSTRAINT [FK_CategoryGroups_Categories] FOREIGN KEY([category_id])
REFERENCES [Categories] ([category_id])
GO
ALTER TABLE [CategoryGroups] CHECK CONSTRAINT [FK_CategoryGroups_Categories]
GO
ALTER TABLE [CategoryGroups] WITH CHECK ADD CONSTRAINT [FK_CategoryGroups_Groups] FOREIGN KEY([group_id])
REFERENCES [Groups] ([group_id])
GO
ALTER TABLE [CategoryGroups] CHECK CONSTRAINT [FK_CategoryGroups_Groups]
Satwa S. RaoMemberi’ve just realized that owner is a reserved word for this scaffolding.
By simply renaming the db field name to the_owner, it worked nicely.
Thought of sharing here 🙂
Cheers,
Satwa
-
AuthorPosts