Un-à-plusieurs relations: mise à Jour à retirer les enfants avec JPA 2.0

J'ai une bidirectionnel un-à-plusieurs relations.

0 ou 1 client <-> Liste des 0 ou plus les commandes de produits.

Cette relation doit être défini ou indéfini sur deux entités:
Sur le côté client, je tiens à mettre la Liste des commandes de produits cédés au client; le client doit alors définir /annuler les ordres choisi automatiquement.
Sur le produit commande de côté, je veux mettre le client à qui l'oder est affecté; que la commande de produit doit ensuite être retiré de son assiged client de la liste et ajouté à la nouvelle attribué client de la liste.

Je veux l'utiliser pur JPA 2.0 annotations et une "fusion" appel à l'entité gestionnaire (avec cascade d'options). J'ai essayé avec le code suivant morceaux, mais il ne fonctionne pas (j'utilise EclipseLink 2.2.0 en tant que fournisseur de persistance)

@Entity
public class Client implements Serializable {
    @OneToMany(mappedBy = "client", cascade= CascadeType.ALL)
    private List<ProductOrder> orders = new ArrayList<>();

    public void setOrders(List<ProductOrder> orders) {
        for (ProductOrder order : this.orders) {
            order.unsetClient();
            //don't use order.setClient(null);
            //(ConcurrentModificationEx on array)
            //TODO doesn't work!
        }
        for (ProductOrder order : orders) {
            order.setClient(this);
        }
        this.orders = orders;
    }

    //other fields /getters /setters
}

@Entity
public class ProductOrder implements Serializable {
    @ManyToOne(cascade= CascadeType.ALL)
    private Client client;

    public void setClient(Client client) {
        //remove from previous client
        if (this.client != null) {
            this.client.getOrders().remove(this);
        }

        this.client = client;

        //add to new client
        if (client != null && !client.getOrders().contains(this)) {
            client.getOrders().add(this);
        }
    }

    public void unsetClient() {
        client = null;
    }

    //other fields /getters /setters
}

Façade de code pour la persistance de client:

//call setters on entity by JSF frontend...
getEntityManager().merge(client)

Façade de code pour la persistance de la commande de produit:

//call setters on entity by JSF frontend...
getEntityManager().merge(productOrder)

Lors de la modification de l'attribution du client sur le bon de commande côté, ça fonctionne bien: Sur le côté client, la commande est supprimée à partir du client précédent de la liste et est ajouté au nouveau client de la liste (si attribué).

MAIS lors de la modification sur le côté client, je ne peux qu'ajouter des commandes (de l'ordre de côté, de l'affectation au nouveau client est effectué), mais il l'ignore quand j'enlève les commandes du client la liste (après l'enregistrement et rafraîchissante, ils sont toujours dans la liste sur le côté client, et sur l'ordre de l'autre, ils sont également toujours attribué à la précédente client.

Juste pour clarifier, je NE souhaitez PAS utiliser un "supprimer" orphelins de l'option: Lors de la suppression d'une commande de la liste, il ne devrait pas être supprimé de la base de données, mais son attribution du client doit être mis à jour (qui est, null), comme défini dans le Client#setOrders méthode. Comment cela peut-il être engagés?


MODIFIER: Grâce à l'aide que j'ai reçu ici, j'ai été en mesure de résoudre ce problème. Voir ma solution ci-dessous:

Le client ("Un" /"propriété" côté) stocke les commandes qui ont été modifiés dans une temporaire terrain.

@Entity
public class Client implements Serializable, EntityContainer {

    @OneToMany(mappedBy = "client", cascade= CascadeType.ALL)
    private List<ProductOrder> orders = new ArrayList<>();

    @Transient
    private List<ProductOrder> modifiedOrders = new ArrayList<>();

    public void setOrders(List<ProductOrder> orders) {
    if (orders == null) {
        orders = new ArrayList<>();
    }

    modifiedOrders = new ArrayList<>();
    for (ProductOrder order : this.orders) {
        order.unsetClient();
        modifiedOrders.add(order);
        //don't use order.setClient(null);
        //(ConcurrentModificationEx on array)
    }

    for (ProductOrder order : orders) {
        order.setClient(this);
        modifiedOrders.add(order);
    }

    this.orders = orders;
    }

    @Override //defined by my EntityContainer interface
    public List getContainedEntities() {
        return modifiedOrders;
}

Sur le façade, lors de la persistance, il vérifie si il y a des entités qui doivent être conservées, trop. Notez que j'ai utilisé une interface pour encapsuler cette logique que ma façade est en fait générique.

//call setters on entity by JSF frontend...
getEntityManager().merge(entity);

if (entity instanceof EntityContainer) {
    EntityContainer entityContainer = (EntityContainer) entity;
    for (Object childEntity : entityContainer.getContainedEntities()) {
        getEntityManager().merge(childEntity);
    }
}

OriginalL'auteur SputNick | 2012-05-17