I'm having problems mapping ManyToOne from a Parent to Child relationship. The OneToMany collection populates lazily fine. However, the inverse to a single entity, does not.
I have a table of Server instances, which is immutable.
When I create a List of Servers, it populates the Collection of Requests that a Server has assigned to it without problems.
When I add a new Request, and select the Server preferred from a dropdown, saveOrUpdate, (or even tried load, and get) it does not populate the Server property in the Request instance.
Server.java
public class Server {
private int serverId;
private List<Request> requests;
...
@OneToMany(mappedBy="server", fetch=FetchType.LAZY)
public List<Request> getRequests() {
return requests;
}
}
Request.java
public class Request {
private int requestId;
private int server_serverId; // foreign key to Server.serverId
private Server server;
...
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="server_serverId", nullable=false, updatable=false, insertable=false}
@ForeignKey(name="server_serverId", inverseName="serverId") // Don't think this really does anything
public Server getServer() {
return server;
}
}
add.jsp (Add Request form)
...
<form:select id="preferred-server" path="server.serverId">
<c:forEach items="${servers}" var="server">
<form:option value="${server.serverId}">${server.serverName}</form:option>
</c:forEach>
</form:select>
...
AddRequestController.java
public class AddRequestController extends SimpleFormController {
...
@Override
protected ModelAndView onSubmit(Object command) throws Exception {
Request request = (Request)command;
try {
logger.info("BEFORE SAVE, request.server = " + request.getServer());
} catch (NullPointerException npe) {
logger.error("onSubmit() caught NPE: " + npe);
}
// Would rather not do these next two lines. Would prefer to saveOrUpdate
// Request, and have it populate server property via server_serverId foreign key.
//Server server = serverDao.loadByServerId(request.getServer_serverId());
//request.setSer开发者_JAVA技巧ver(server);
//Added this instead, which calls getHibernateTemplate().refresh(server, LockMode.READ)
serverDao.refreshServer(request.getServer());
requestDao.addRequest(request); // calls getHibernateTemplate.saveOrUpdate(request)
try {
logger.info("AFTER SAVE, request.server = " + request.getServer());
} catch (NullPointerException npe) {
logger.error("onSubmit() caught NPE: " + npe);
}
return new ModelAndView(getSuccessView(), "request", request);
}
}
I've tried virtually every combination of Annotation mapping I could find online, and this is the setup that works with fetching a Collection of Requests.
Now, of course, I can get my Request command object from the SimpleFormController, load the Server object based on what the user selects, and persist it that way--but that's not the point of relationship mapping, now is it?
Any suggestions? Let me know if you require any other code.
Using: Spring 2.5, Hibernate 3.2.5, Sybase DB
The problem is that Request
is the owning side, so you need to add the server to the request, i.e. call setServer()
. The server
field is the one responsible for the corresponding column in your database.
It is not sufficient to add the request to the list since that is just the inverse mapping. If you'd set the server in the request and then reload the server from the db, the request should be automatically added to the list (although you'd normally not do that but manually add the server to the list as well).
Thus the Request should look like this:
public class Request {
private int requestId;
//I don't see any need for this
//private int server_serverId; // foreign key to Server.serverId
private Server server;
...
@ManyToOne ( fetch=FetchType.LAZY ) //employ lazy loading, you can put that on @OneToMany too
@JoinColumn( name="server_serverId", nullable=false }
public Server getServer() {
return server;
}
}
精彩评论