Чтение незафиксированных сгенерированных идентификаторов в Spring / JPA - PullRequest
1 голос
/ 21 октября 2011

Я пытаюсь получить сгенерированный идентификатор недавно созданного объекта в транзакции, но когда я пытаюсь прочитать значение идентификатора, оно становится пустым.Я предполагаю, что это потому, что транзакция еще не была принята, а идентификатор сущности еще не создан.

Я использую 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.

Ответы [ 2 ]

0 голосов
/ 25 октября 2011

Поскольку вы используете последовательность TABLE, идентификатор будет назначен на ваш вызов persist (). Вы отделяете или сериализуете объекты? Вам может потребоваться вернуть идентификатор, назначенный в персистенте, вашему клиенту.

0 голосов
/ 21 октября 2011

Попробуйте

entityManager.flush();

после сохранения новой сущности. Это заставит провайдера JPA синхронизировать ваш постоянный контекст с базовой базой данных, и как часть этого будет сгенерирован любой идентификатор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...