Я пытаюсь получить сгенерированный идентификатор недавно созданного объекта в транзакции, но когда я пытаюсь прочитать значение идентификатора, оно становится пустым.Я предполагаю, что это потому, что транзакция еще не была принята, а идентификатор сущности еще не создан.
Я использую Spring MVC и транзакции (использую @Transactional в моем сервисе) и использую JPA для данныхслой.Я не эксперт в управлении транзакциями, поэтому я даже не уверен, возможно ли это.Это пример кода, выполняемого на уровне представления (Spring Portlet MVC):
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();
EDIT:
Вот сущности.Я использую Oracle db.
@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<Item> siblings = parent.getChildren();
int index = siblings.indexOf(this);
if (index > 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<Item> siblings = parent.getChildren();
int index = siblings.indexOf(this);
int numItems = siblings.size();
if ((numItems > 1) && (index < (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<Item> children = new ArrayList<Item>();
@Transient
private String path;
@Transient
private boolean open;
@Transient
private Collection<Link> orderedLinks;
/**
* @return Returns the children.
*/
public List<Item> getChildren() {
return children;
}
/**
* @param children
* The children to set.
*/
public void setChildren(List<Item> 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<? extends Item> items) {
for (Item item : items)
addItem(item);
}
/**
*
* @param items
*/
public void removeItems(List<? extends Item> 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<Folder> getFolderList() {
List<Folder> folderList = new ArrayList<Folder>();
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<Folder> getFolderList(Folder excludeFolder) {
List<Folder> folderList = new ArrayList<Folder>();
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<Folder> getParentList() {
List<Folder> parentList = new ArrayList<Folder>();
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<Folder> folderList, Folder excludeFolder) {
// Don't add the exclude folder to the list
if (excludeFolder != null && 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() + " > ");
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<Item> 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<Link> getLinks() {
List<Item> children = getChildren();
List<Link> links = new ArrayList<Link>(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<Folder> getChildFolders() {
List<Folder> folderList = new ArrayList<Folder>();
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<Link> getOrderedLinks() {
return orderedLinks;
}
public void setOrderedLinks(Collection<Link> 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() >>> 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 && url.indexOf(":/") == -1)
url = "http://" + url;
this.url = url;
}
}
Контроллер вызывает DAO, который вызывает entityManager.merge () (и я попытался включить entityManger.flush ()).Я также использую OpenEntityInManagerInterceptor.