Note that there are some explanatory texts on larger screens.

plurals
  1. POReading uncommitted generated IDs in Spring / JPA
    primarykey
    data
    text
    <p>I am trying to retrieve the generated ID of a newly created Entity within a transaction, but when I try to read the ID value it is null. I assume this is because the transaction has not yet been committed and the Entity's ID has yet to be created.</p> <p>I am using Spring MVC and transactions (using @Transactional on my service), and using JPA for the data layer. I'm not an expert in transaction management, so I'm not even sure if this is possible. This is example code being executing in the presentation layer (Spring portlet MVC):</p> <pre><code>Long parentId = getParentId(); Folder parentFolder = linksService.getItem(parentId, Folder.class); Folder newFolder; newFolder = new Folder(); newFolder.setName("new folder"); newFolder.setParent(parentFolder); parentFolder.addItem(newItem); linksService.saveItem(parentFolder); // this calls entityManager.merge(parentFolder) // this returns null String itemId = newFolder.getItemId(); </code></pre> <p>EDIT:</p> <p>Here are the entities. I am using Oracle db.</p> <pre><code>@Entity @Table(name = "LINK_ITEM") @DiscriminatorColumn(name = "ITEM_TYPE") public abstract class Item { /** * The Id of this item */ @Id @TableGenerator(name = "table_gen", allocationSize = 1) @GeneratedValue(strategy = GenerationType.TABLE, generator = "table_gen") @Column(name = "ITEM_ID") private Long itemId; /** * The name of this item */ private String name; /** * the parent item of this item */ @ManyToOne @JoinColumn(name="PARENT_ID") private Item parent; /** * The user ID that owns this item */ private String owner; /** * @return Returns the itemId. */ public Long getItemId() { return itemId; } /** * @param itemId * The itemId to set. */ public void setItemId(Long itemId) { this.itemId = itemId; } /** * @return Returns the name. */ public String getName() { return name; } /** * @param name * The name to set. */ public void setName(String name) { this.name = name; } /** * @return Returns the owner. */ public String getOwner() { return owner; } /** * @param owner * The owner to set. */ public void setOwner(String owner) { this.owner = owner; } /** * @return Returns the parent. */ public Item getParent() { return parent; } /** * @param parent * The parent to set. */ public void setParent(Item parent) { this.parent = parent; } /** * Returns the depth of this object in the folder tree. 0 is the top folder, * 1 is one level down, etc. * * @return Returns the depth. */ @Transient public long getDepth() { long i = 0; for (Item item = this; item.getParent() != null; item = item .getParent()) { ++i; } return i; } /** * Changes the parent folder of this item and updates links / children * appropriately. * * @param parentFolder */ public void updateParent(Folder parentFolder) { removeFromParent(); parentFolder.addItem(this); } /** * Removes this item from it's parent folder, if it has one. */ public void removeFromParent() { if (getParent() != null) { ((Folder) getParent()).removeItem(this); } } public void moveUp() { if (getParent() == null) { return; } Folder parent = (Folder) getParent(); List&lt;Item&gt; siblings = parent.getChildren(); int index = siblings.indexOf(this); if (index &gt; 0) { Item previousItem = siblings.get(index - 1); siblings.set(index, previousItem); siblings.set(index - 1, this); } } public void moveDown() { if (getParent() == null) { return; } Folder parent = (Folder) getParent(); List&lt;Item&gt; siblings = parent.getChildren(); int index = siblings.indexOf(this); int numItems = siblings.size(); if ((numItems &gt; 1) &amp;&amp; (index &lt; (numItems - 1))) { Item nextItem = (Item) siblings.get(index + 1); siblings.set(index, nextItem); siblings.set(index + 1, this); } } /** * Returns the String representation of this Item. */ @Override public String toString() { return "itemId=" + this.getItemId() + "; name=" + this.getName() + "; owner=" + this.getOwner(); } } @Entity @DiscriminatorValue("F") public class Folder extends Item { @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name="PARENT_ID", referencedColumnName="ITEM_ID") private List&lt;Item&gt; children = new ArrayList&lt;Item&gt;(); @Transient private String path; @Transient private boolean open; @Transient private Collection&lt;Link&gt; orderedLinks; /** * @return Returns the children. */ public List&lt;Item&gt; getChildren() { return children; } /** * @param children * The children to set. */ public void setChildren(List&lt;Item&gt; children) { this.children = children; } /** * Changes the parent folder of this item and updates links / children * appropriately. * * @param parentFolder */ public void updateParent(Folder parentFolder) { super.updateParent(parentFolder); // update the path since the parent folder has changed updatePath(); } /** * @param newItem */ public void addItem(Item newItem) { newItem.setParent(this); getChildren().add(newItem); } /** * @param item */ public void removeItem(Item item) { getChildren().remove(item); item.setParent(null); } /** * * @param items */ public void addItems(List&lt;? extends Item&gt; items) { for (Item item : items) addItem(item); } /** * * @param items */ public void removeItems(List&lt;? extends Item&gt; items) { for (Item item : items) removeItem(item); } /** * Returns a list of Folder objects that are the subfolders of this folder. * This folder is also included at the top of the list. * * @return * @throws ServiceException */ @Transient public List&lt;Folder&gt; getFolderList() { List&lt;Folder&gt; folderList = new ArrayList&lt;Folder&gt;(); buildFolderList(folderList, null); return folderList; } /** * Returns a list of Folder objects that are the subfolders of this folder. * This folder is also included at the top of the list. This method will * exclude the "excludeFolder" and it's subfolders from the list. * * @param excludeFolder * @return */ @Transient public List&lt;Folder&gt; getFolderList(Folder excludeFolder) { List&lt;Folder&gt; folderList = new ArrayList&lt;Folder&gt;(); buildFolderList(folderList, excludeFolder); return folderList; } /** * Returns a recursive list of the parent folder of this folder. Includes * this folder in the list. * * @return */ @Transient public List&lt;Folder&gt; getParentList() { List&lt;Folder&gt; parentList = new ArrayList&lt;Folder&gt;(); Folder currentFolder = this; parentList.add(currentFolder); while (currentFolder.getParent() != null) { currentFolder = (Folder) currentFolder.getParent(); parentList.add(currentFolder); } // reverse the ordering Collections.reverse(parentList); return parentList; } /** * Private method called recursively to build a list of Folder's and * subfolders of the parentFolder. * * @param folderList * @param parentFolder * @param excludeFolder */ private void buildFolderList(List&lt;Folder&gt; folderList, Folder excludeFolder) { // Don't add the exclude folder to the list if (excludeFolder != null &amp;&amp; this.equals(excludeFolder)) { return; } folderList.add(this); if (!isFolderEmpty()) { for (Item item : getChildren()) { if (item instanceof Folder) { ((Folder) item).buildFolderList(folderList, excludeFolder); } } } } /** * @return Returns the folderEmpty. */ @Transient public boolean isFolderEmpty() { return children == null || children.isEmpty() || children.size() == 0; } /** * */ private void updatePath() { StringBuffer strBuffer = new StringBuffer(""); strBuffer.append(getName()); Item parent = getParent(); while (parent != null) { strBuffer.insert(0, parent.getName() + " &gt; "); parent = parent.getParent(); } this.path = strBuffer.toString(); } /** * @return Returns the path of this folder. */ public String getPath() { if (this.path == null || this.path.length() == 0) updatePath(); return this.path; } /** * @param path * The path to set. */ protected void setPath(String path) { this.path = path; } public Item find(Long itemId) { if (itemId.equals(getItemId())) return this; Item item = null; List&lt;Item&gt; children = getChildren(); for (Item currentItem : children) { if (currentItem.getItemId().equals(itemId)) { item = currentItem; break; } else if (currentItem instanceof Folder) { item = ((Folder) currentItem).find(itemId); if (item != null) break; } } return item; } /** * Returns the String representation of this Folder. */ @Override public String toString() { return super.toString() + "; path=" + this.getPath(); } /** * * @return a list of Link objects that this Folder holds. */ @Transient public List&lt;Link&gt; getLinks() { List&lt;Item&gt; children = getChildren(); List&lt;Link&gt; links = new ArrayList&lt;Link&gt;(children.size() - (children.size() / 2)); for (Item item : children) { if (item instanceof Link) { links.add((Link) item); } } return links; } /** * Returns the child Folders of this Folder and their child Folders, etc. * * @return */ @Transient public List&lt;Folder&gt; getChildFolders() { List&lt;Folder&gt; folderList = new ArrayList&lt;Folder&gt;(); buildFolderList(folderList, null); folderList.remove(this); return folderList; } public boolean isOpen() { return open; } @Transient public boolean isClosed() { return !open; } public void setOpen(boolean open) { this.open = open; } public Collection&lt;Link&gt; getOrderedLinks() { return orderedLinks; } public void setOrderedLinks(Collection&lt;Link&gt; orderedLinks) { this.orderedLinks = orderedLinks; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || (obj.getClass() != this.getClass())) { return false; } Folder folder = (Folder) obj; return this.getItemId() == folder.getItemId(); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int var = (int) (this.getItemId().longValue() ^ (this.getItemId() .longValue() &gt;&gt;&gt; 32)); int hash = 7; hash = 31 * hash + var; return hash; } } @Entity @DiscriminatorValue("L") public class Link extends Item { private String url; public Link() { } public Link(String url) { this.url = url; } /** * @return Returns the url. */ public String getUrl() { return url; } /** * @param url * The url to set. */ public void setUrl(String url) { if (url != null &amp;&amp; url.indexOf(":/") == -1) url = "http://" + url; this.url = url; } } </code></pre> <p>The Controller is calling the DAO, which calls entityManager.merge() (and I tried including entityManger.flush()). I also use OpenEntityInManagerInterceptor.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload