1


0

Spring / JPAでコミットされていない生成IDを読み取る

トランザクション内で新しく作成されたエンティティの生成されたIDを取得しようとしていますが、ID値を読み取ろうとするとnullです。 これは、トランザクションがまだコミットされておらず、エンティティのIDがまだ作成されていないためだと思います。

Spring MVCとトランザクション(サービスで@Transactionalを使用)を使用し、データレイヤーにJPAを使用しています。 私はトランザクション管理の専門家ではないので、これが可能かどうかさえわかりません。 これは、プレゼンテーション層(Springポートレット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();

編集:

エンティティは次のとおりです。 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 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 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 children = new ArrayList();

@Transient
private String path;

@Transient
private boolean open;

@Transient
private Collection orderedLinks;

/**
 * @return Returns the children.
 */
public List getChildren() {
    return children;
}

/**
 * @param children
 *            The children to set.
 */
public void setChildren(List 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 getFolderList() {
    List folderList = new ArrayList();
    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 getFolderList(Folder excludeFolder) {
    List folderList = new ArrayList();
    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 getParentList() {
    List parentList = new ArrayList();
    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 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 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 getLinks() {
    List children = getChildren();
    List links = new ArrayList(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 getChildFolders() {
    List folderList = new ArrayList();
    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 getOrderedLinks() {
    return orderedLinks;
}

public void setOrderedLinks(Collection 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;
}
}

Controllerは、entityManager.merge()を呼び出すDAOを呼び出しています(entityManger.flush()を含めてみました)。 OpenEntityInManagerInterceptorも使用します。

2 Answer


0


Try

entityManager.flush();

新しいエンティティを保存した後。 これにより、JPAプロバイダーは永続コンテキストを基になるデータベースと同期させ、この一環としてIDが生成されます。


0


TABLEシーケンスを使用しているため、persist()呼び出しでIDが割り当てられます。 オブジェクトをデタッチまたはシリアル化していますか? persistで割り当てられたIDをクライアントに返す必要がある場合があります。