How to add and display data from 2 tables?How to add and display data from 2 tables?https://liferay.dev/en/c/message_boards/find_thread?p_l_id=119785333&threadId=1124612982024-03-28T09:53:56Z2024-03-28T09:53:56ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1125086332019-02-28T08:54:52Z2019-02-28T08:54:52Zthank you very much for the information! you'r a boss.Tiago Machado2019-02-28T08:54:52ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1125005872019-02-27T17:43:25Z2019-02-27T17:43:25ZYou can construct DTOs, that's up to you. Even using service builder "fake entities", you can create managed DTOs that are not bound to database tables.<br /><br />It doesn't, however, eliminate the need to pull the DB entities, plus it adds overhead to marshal the entities to/from the DTOs.<br /><br />Everything comes at a cost, you just have to know how much you're willing to pay.<br /><br />The referenced post, for example, presents a clean design where changes can be isolated to the various layers of concern. What it excludes is the runtime overhead involved with that level of separation.<br /><br />For every data retrieve, you marshal to the view model. When your UI populates the view model, you have to marshal back to the entity for persistence requirement. All of this is processed on every retrieve and on every update, and this overhead negatively affects your overall capacity.<br /><br />So sure, from a maintenance perspective a changed entity can require a UI changes, increasing the cost of the development effort. The problem is that this cost can be measured and evaluated, so it appears to be clear. But that overhead, the loss of capacity, the increased response time with the marshaling effort, all of these things represent an invisible cost that is never measured, evaluated or estimated.<br /><br />I would argue that the hidden cost far surpasses the apparent cost for a change request.David H Nebinger2019-02-27T17:43:25ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1125000122019-02-27T17:25:51Z2019-02-27T17:25:51ZThank you very much about the info!<br />I'm searching about it too xD<br />what if i created classes for the view? or doest make any sense?<br />i was seeing this post here: https://stackoverflow.com/questions/23648832/viewmodels-in-mvc-mvvm-seperation-of-layers-best-practices<br />i know that is c# but you get the idea...<br /><br />a model to view the data only. is that possible here?<br /><br />thanks!Tiago Machado2019-02-27T17:25:51ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124997252019-02-27T17:09:39Z2019-02-27T17:09:39Z<html><head></head><body>In MovieImpl, you could do something like:<br><pre><code>private Author author = null;
public Author getAuthor() {
if (author == null) {
author = AuthorLocalServiceUtil.getAuthorByMovieId(getMovieId());
}
return author;
}</code></pre><br>This was the other option that I had suggested, it doesn't require overrides of all of the getters in the MovieLocalServiceImpl to populate Author.<br><br>By caching the value, though, you run the risk of the stale data if someone changes the author after the value had been fetched.<br><br>You could not use the caching option, opting instead to always return the fetched value:<br><pre><code>public Author getAuthor() {
return AuthorLocalServiceUtil.getAuthorByMovieId(getMovieId());
}</code></pre><br>This avoids the stale data issue, but it means that any time getAuthor() is called it could be a new db retrieval.</body></html>David H Nebinger2019-02-27T17:09:39ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124991412019-02-27T16:56:02Z2019-02-27T16:56:02ZI think I didn't explain well what i wanted to do now.<br /><br />Search container is pretty good. what I wanted to ask is, if there is another way of showing the data without having to override de getter, is there an option to that? could I create for example a package and there a view model for just displaying all the data isntead of overriding the getter?<br /><br />or is there any liferay tool to implement a class with code that would provide the JSP with the data do show, and in the JSP all i needed to do is call the class?<br />I'm just curious about the alternatives <img alt="emoticon" src="@theme_images_path@/emoticons/happy.gif" >Tiago Machado2019-02-27T16:56:02ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124988472019-02-27T16:36:27Z2019-02-27T16:36:27ZYou can build a raw HTML table, if that's what you want to manage on your own.<br /><br />Liferay tends to use the search container because of the contained functionality; column sorting, pagination, row highlighting, model bean handling, column types like an external JSP page for encapsulate column rendering code, ...<br /><br />But it is not the only way. Anything you can build using HTML DOM, CSS and JS, you can build into your portlet.<br /><br />It just depends how much you want to manage yourself.David H Nebinger2019-02-27T16:36:27ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124979922019-02-27T16:11:22Z2019-02-27T16:11:22ZHey David, i want to go further if possible, is there a way to display the data like i did but in a different way? for example, could i create a model for the view?<br />or can I implement code to view the data i wish in some portlet action command class and then call it in the jsp without the search container?<br /><br />the view model seems good, whenever i would need to view something I would have it there. but I need some documentation, would apreciate your suggestion, as always, if you have some useful link for me to study that and implement it please share with me.<br /><br />thank you!!!Tiago Machado2019-02-27T16:11:22ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124888272019-02-27T10:45:50Z2019-02-27T10:45:50ZThank you again for the answer!<br /><br />Damn you are an angel! are you single? ;) just kidding <img alt="emoticon" src="@theme_images_path@/emoticons/happy.gif" ><br /><br />That did the trick, i just needed to set the author in the AddMovieAndAuthor method, create a finder in the AuthorServiceImpl to get the author by the movie id and, override the getter like you told me, just one thing there, i had to change the long to int or i would get an error on the super telling me that i cant invoke directly the abstract method.<br /><br />after that i just needed to change in the JSP where i was telling the porperty, because there is no property with the info i just persisted ofc... so i replaced the property tag with value tag and now i can see the info from the 2 tables.<br /><br />thanks a lot!!!Tiago Machado2019-02-27T10:45:50ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124832622019-02-27T03:44:06Z2019-02-27T03:44:06Z<html><head></head><body>Okay, so the issue is in your service layer...<br><br>MovieLocalServiceImpl's addMovie() should not set the author because, well, you're just adding a movie.<br><br>However, addMovieAndAuthor() should be:<br><pre><code>public Movie addMovieAndAuthor(long groupId, String movieName, String description, int rating,
String authorName, String biography, ServiceContext serviceContext) throws PortalException {
// add the new movie
Movie movie = addMovie(groupId, movieName, description, rating, serviceContext);
// now create the author
Author author = _authorLocalService.addAuthor(movie.getMovieId(), authorName, biography, serviceContext);
// set the author back to the movie
movie.setAuthor(author);
// nothing else to update, just return the new movie.
return movie;
}</code></pre><br>Now the problem with your JSP though is that you're using MovieLocalServiceUtil.getMovies(long, long) but you haven't overridden it to do the author lookups. You'd need something like the following in MovieLocalServiceImpl:<br><pre><code>@Override
public List<movie> getMovies(long startPos, long endPos) {
&nbsp; // first fetch the list of movies
&nbsp; List<movie> movies = super.getMovies(startPos, endPos);
&nbsp; // now need to fetch the authors
&nbsp; if ((movies != null) &amp;&amp; (! movies.isEmpty())) {
&nbsp; Author author;
&nbsp; for (Movie movie : movies) {
&nbsp; // you'll need a finder in AuthorLocalServiceImpl to get the author for the given movie id.
&nbsp; author = _authorLocalService.getAuthorByMovieId(movie.getMovieId());
&nbsp; // Note that normally a get method in the service layer will throw one of the NotFound exceptions
&nbsp; // if there was no record found. So either it will throw one or perhaps you're returning null, either
// way it may be something you need to deal with.
// save back to the movie
&nbsp; movie.setAuthor(author);
&nbsp; }
&nbsp; }
&nbsp; return movies;
}</movie></movie></code></pre><br>But this was what I meant when I said you'd have to override the getters in the MovieLocalServiceImpl so that you could fetch and populate authors before returning.</body></html>David H Nebinger2019-02-27T03:44:06ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124814762019-02-26T22:49:58Z2019-02-26T22:49:58Z<html><head></head><body>Yeah, sorry, I have the following code:<br><br>MovieImpl:<pre><code>@ProviderType
public class MovieImpl extends MovieBaseImpl {
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;private Author author;
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public MovieImpl() {
&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public Author getAuthor() {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return author;
&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public void setAuthor(Author author) {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this.author = author;
&nbsp;&nbsp; &nbsp;}
}</code></pre>MovieLocalServiceImpl:<pre><code>public class MovieLocalServiceImpl extends MovieLocalServiceBaseImpl {
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;//Author author;
&nbsp;&nbsp; &nbsp;public Movie addMovie(long groupId, String movieName, String description,&nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int rating, ServiceContext serviceContext) throws PortalException {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//Group is used for the scoping the Movie entity to the site
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Group group = groupPersistence.findByPrimaryKey(groupId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//getting the user, first get the user id go get the user : userPersistence || userLocalService
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;long userId = serviceContext.getUserId();
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;User user = userLocalService.getUserById(userId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//Generate primary key for the new movie - referencing the movie class in the specific movie about to create
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;long movieId = counterLocalService.increment(Movie.class.getName()); //counterLocalService helps with primary key
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//create new movie object
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Movie movie = super.createMovie(movieId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//populate all movie object fields
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setCompanyId(group.getCompanyId());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setGroupId(groupId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setUserId(userId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setDescription(description);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setMovieName(movieName);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setRating(rating);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setUserName(user.getScreenName());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setModifiedDate(serviceContext.getModifiedDate(new Date()));
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.setCreateDate(serviceContext.getCreateDate(new Date()));
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//movie.setAuthor(author);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//test
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//System.out.println("autho: " + movie.getAuthor());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//System.out.println("author name test: " + movie.getAuthor().getAuthorName());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//persist the movie
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie = super.addMovie(movie);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//add permission resources
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boolean portletActions = false;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boolean addGroupPermissions = true;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boolean addGuestPermissions = true;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//when creating the movie, we create the permission resource along it.
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;resourceLocalService.addResources(group.getCompanyId(),groupId, userId, Movie.class.getName(),&nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movie.getMovieId(), portletActions, addGroupPermissions, addGuestPermissions);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return movie;
&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public Movie addMovieAndAuthor(long groupId, String movieName, String description, int rating,
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String authorName, String biography, ServiceContext serviceContext) throws PortalException {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Movie movie = addMovie(groupId, movieName, description, rating, serviceContext);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Author author = AuthorServiceUtil.addAuthor(movie.getMovieId(), authorName, biography, serviceContext);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author = AuthorLocalServiceUtil.addAuthor(author);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//movie.setAuthor(author);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return addMovie(movie);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;}</code></pre>AuthorLocalServiceImpl:<pre><code>public class AuthorLocalServiceImpl extends AuthorLocalServiceBaseImpl {
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public Author addAuthor(long movieId, String authorName, String biography, ServiceContext serviceContext)&nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throws PortalException {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Movie movie = MovieLocalServiceUtil.getMovie(movieId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;long userId = serviceContext.getUserId();
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;User user = UserLocalServiceUtil.getUser(userId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//generate the author primary key
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;long authorId = counterLocalService.increment(Author.class.getName());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//create author obj
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Author author = authorLocalService.createAuthor(authorId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//set author properties
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setCompanyId(movie.getCompanyId());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setGroupId(movie.getGroupId());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setAuthorId(authorId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setAuthorName(authorName);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setBiography(biography);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setUserName(user.getScreenName());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setMovieId(movieId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setUserId(userId);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setCreateDate(new Date());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;author.setModifiedDate(new Date());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//persist data
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;super.addAuthor(author);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return author;
&nbsp;&nbsp; &nbsp;}</code></pre>AddMovieMVCActionCommand:<pre><code>
@Component(
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;immediate = true,
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;property = {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"javax.portlet.name=" + MoviesPortletKeys.MOVIES,
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"MVC.command.name=" + MVCCommandNames.ADD_MOVIE,
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;},&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;service = MVCActionCommand.class
)
public class AddMovieMVCActionCommand extends BaseMVCActionCommand {
&nbsp;&nbsp; &nbsp;@Reference
&nbsp;&nbsp; &nbsp;MovieService movieService;
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;public static final Log log = LogFactoryUtil.getLog(Movie.class);
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;@Override
&nbsp;&nbsp; &nbsp;protected void doProcessAction(ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ServiceContext serviceContext = ServiceContextFactory.getInstance(Movie.class.getName(), actionRequest);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String movieName = ParamUtil.getString(actionRequest, "movie");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String description = ParamUtil.getString(actionRequest, "description");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int rating = ParamUtil.getInteger(actionRequest, "rating");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String authorName = ParamUtil.getString(actionRequest, "author");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String biography = ParamUtil.getString(actionRequest, "biography");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;try {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;MovieLocalServiceUtil.addMovieAndAuthor(themeDisplay.getScopeGroupId(), movieName, description, rating, authorName,&nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;biography, serviceContext);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;SessionMessages.add(actionRequest, "movie-addded");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;hideDefaultSuccessMessage(actionRequest);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sendRedirect(actionRequest, actionResponse);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}catch (MovieValidationException e){
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;actionResponse.setRenderParameter("mvcRenderCommandName", MVCCommandNames.EDIT_MOVIE);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}catch (PortalException e){
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;log.error(e);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;SessionErrors.add(actionRequest, MVCCommandNames.EDIT_MOVIE);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;}
}
</code></pre><br><br>update.jsp (This is actually add movie. bad naming here)<pre><code><portlet:renderurl var="goBackURL">
&nbsp;&nbsp; &nbsp;<portlet:param name="jspPage" value="/view.jsp" />
</portlet:renderurl>
<h1>Add Movie</h1>
<portlet:actionurl name="<%=MVCCommandNames.ADD_MOVIE %>" var="addMovieURL"></portlet:actionurl>
&nbsp; &nbsp; &nbsp; &nbsp; <aui:form action="<%= addMovieURL %>" name="<portlet:namespace />fm">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:fieldset>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:input name="movie" />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:input name="description" />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:input name="rating" />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:input name="author" />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:input name="biography" />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </aui:fieldset>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:button-row>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:button type="submit"></aui:button>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <aui:button type="cancel" onclick="<%= goBackURL.toString() %>"></aui:button>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </aui:button-row>
&nbsp; &nbsp; &nbsp; &nbsp; </aui:form></code></pre>view_test.jsp (all data is viewed here)<pre><code><h1 align="center">Movies List</h1>
<portlet:actionurl var="goBackURL">
&nbsp;&nbsp; &nbsp;<param name="jspPage" value="/view.jsp">
</portlet:actionurl>
<liferay-portlet:renderurl varimpl="iteratorURL">
&nbsp;&nbsp; &nbsp;<liferay-portlet:param name="jspPage" value="/view_test.jsp" />
</liferay-portlet:renderurl>
<liferay-ui:search-container emptyresultsmessage="there-are-no-movies" headernames="movieName, description, rating, action" iteratorurl="<%=iteratorURL%>" delta="10" curparam="sc1" deltaconfigurable="true">
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-results>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;%
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int totalMovies = MovieLocalServiceUtil.getMoviesCount();
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;results = MovieLocalServiceUtil.getMovies(searchContainer.getStart(), searchContainer.getEnd());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;searchContainer.setTotal(totalMovies);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;searchContainer.setResults(results);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;%&gt;
&nbsp;&nbsp; &nbsp;</liferay-ui:search-container-results>
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-row classname="com.liferay.training.movies.model.Movie" keyproperty="movieId" modelvar="currentMovie">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-portlet:renderurl varimpl="rowURL">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<portlet:param name="backURL" value="<%=currentURL %>" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<portlet:param name="jspPage" value="/view_movie.jsp" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<portlet:param name="movieId" value="<%=String.valueOf(currentMovie.getMovieId()) %>" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;</liferay-portlet:renderurl>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-row-parameter name="rowURL" value="<%=rowURL.toString() %>" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-column-text href="<%=rowURL %>" name="Name" property="movieName" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-column-text href="<%=rowURL %>" name="description" property="description" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-column-text href="<%=rowURL %>" name="rating" property="rating" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &lt;%--
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-column-text href="<%=rowURL %>" name="author" property="<%=currentMovie.getAuthor().getAuthorName() %>" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-column-text href="<%=rowURL %>" name="biography" property="<%=currentMovie.getAuthor().getBiography() %>" />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;--%&gt;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<liferay-ui:search-container-column-jsp align="center" path="/button.jsp" />
&nbsp;&nbsp; &nbsp;</liferay-ui:search-container-row>
&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;<liferay-ui:search-iterator searchContainer="<%=searchContainer %>" paginate="<%=true %>" />
</liferay-ui:search-container>
<aui:button-row>
&nbsp;&nbsp; &nbsp;<aui:button type="cancel" onclick="<%=goBackURL.toString() %>"></aui:button>
</aui:button-row>
</code></pre><br>Thanks a lot!</body></html>Tiago Machado2019-02-26T22:49:58ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124785612019-02-26T18:57:58Z2019-02-26T18:57:58ZWell, the NPE comes from your code clearly; I can't really help you with what I don't have.<br /><br />David H Nebinger2019-02-26T18:57:58ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124770292019-02-26T18:00:26Z2019-02-26T18:00:26ZHey, I'm trying really hard but I'm not being able to do it. I'm trying what you told, i created getter, setter and a private Author in the MovieImpl.<br /><br />Then in the MovieLocalServiceImpl I added a private Author author; and setted the author in the addMovie and AddMovieAndAuthor method but im getting null pointer when i add a new movie<br /><br />i added the property too in the jsp inside the search container, -> property="<%=currentMovie.getAuthor().getAuthorName() %>"<br /><br />what am I doing wrong?<br /><br />I printed the movie.getAuthor and its null, if i comment the setter in the MovieLocalServiceImpl and the data is persisted in the 2 tables from the same form. but if i try to do that i get nullpointer. I know I'm doing something wrong but I'm not getting it.<br /><br />One more thing just to understand a little bit more, since I'm persisting the data when i add a movie (the movie and author data), and then im showing only the movie data in the search container (the obj is the show both movie and author as i said) when I'm setting the author to the movie, exposing the author to the movie, after the adding the data wont i lose the reference?<br /><br />can you help me understand a little more and tell me what am I doing wrong please? <br />thanks a lot!<br /><br />(im sorry with the post above, i dont know what happened, i actually writted the text before and Published it but it didnt appear and i could edit)Tiago Machado2019-02-26T18:00:26ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124764512019-02-26T17:49:43Z2019-02-26T17:49:43ZRE: How to add and display data from 2 tables?Tiago Machado2019-02-26T17:49:43ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124708972019-02-26T14:07:53Z2019-02-26T14:07:53ZSo the search container is only going to handle a single entity class.<br /><br />So the trick here is to expose the author entity as part of the movie entity. You can modify your MovieImpl (the implementation of your Movie entity) and include a getter for Author. Then you can either modify your getters in MovieLocalServiceImpl to fetch the author and populate the field, or you could use the static AuthorLocalServiceUtil to fetch the author on demand.<br /><br />For the getter overrides, you would have a local Author field in MovieImpl and a setAuthor() method, then in each of your MovieLocalServiceImpl methods that can get one or more Movies, you add code to fetch the Author instance and use setAuthor() to assign it.<br /><br />For the on demand, I normally have a local Author field in MovieImpl and the getAuthor() method. The getAuthor() checks if the field is null; if it is, use the AuthorLocalServiceUtil to fetch the Author and set to the local field, then return the value. It's a lazy fetch (only fetches when needed) and caches the value. It suffers though in that it can potentially cache a stale Author if it is later changed for the movie, so you have to figure out if you need to deal with this or not.<br /><br />Typically you choose depending upon whether the related entity will always be used or not; since you are showing as part of the listing for the movie, the prefetch approach makes more sense than the on demand approach (although on demand is often easier to implement).David H Nebinger2019-02-26T14:07:53ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124688392019-02-26T12:37:06Z2019-02-26T12:37:06ZHey David, i managed to do what you suggested, the addMovieAndAuthor method is working fine, and i'm adding the movie data to movie table and author data to author table.<br /><br />But im having a little toubling showing the results, before i was showing the movies using the search container, worked fine, but how can I display the data from the two tables? i want to show the movies and author tables all in one. do i need to use join? or is there any other method?<br /><br />I tried to do like before but im getting "com.liferay.training.movies.model.impl.AuthorImpl cannot be cast to com.liferay.training.movies.model.Movie"<br /><br />What i tried was to add another search container row giving it className of the Author, so i had 2 search container rows, one for the Movie and the other for the Author, but i guess i cant do that.<br /><br />Can you give me some hand here in how to do this?<br />Thanks!Tiago Machado2019-02-26T12:37:06ZRE: How to add and display data from 2 tables?Tiago Machadohttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124635532019-02-25T22:39:42Z2019-02-25T22:39:42ZThank you a lot David! that sounds pretty good! gonna give it a try <img alt="emoticon" src="@theme_images_path@/emoticons/happy.gif" ><br /><br />Very helpful. thanksTiago Machado2019-02-25T22:39:42ZRE: How to add and display data from 2 tables?David H Nebingerhttps://liferay.dev/en/c/message_boards/find_message?p_l_id=119785333&messageId=1124618982019-02-25T18:58:16Z2019-02-25T18:58:16ZAssuming you have an addMovie() method in your service layer, it would return the new Movie instance. From thare you can get the movieId and use it for a corresponding addAuthor() call in your service layer.<br /><br />For the next level, you might consider that these are all part of the same transaction. In this case, you may want to have an additional addMovieAndAuthor() method in the MovieLocalServiceImpl. Since these are part of the same service layer, you'll find that MovieLocalServiceImpl has an injected AuthorLocalService so you can piggyback one call to another.<br /><br />This will keep the addition of a movie and an author within the same transaction scope.<br /><br />Your addMovieAndAuthor() method would first invoke addMovie() and, using the movieId in the returned Movie object, can then call addAuthor() to complete the work.David H Nebinger2019-02-25T18:58:16ZHow to add and display data from 2 tables?Tiago Ma