Problem when create objects programmatically SQL.

I have the next situation.
Entities:
Invoice, InvoiceLine, Article, and Tag.
Tag identifies unequivocally every article of every invoice line.
InvoiceLine has quantity, price, totalPrice, article and tags.
In the InvoiceEdit screen I can create new InvoiceLines with its articles.
InvoiceLineEdit has the articleField and a button “Create Tags”.
When “Create Tags” is pressed, it calls to a method (createTags()) of TagServiceBean that implements TagService. createTags() create many tags as quantity attribute tells.

In TagServiceBean:

@Override
@Transactional
public Collection<Tag> createTags(LineaFactura lineaFactura, Integer amount) {
    checkPermission(EntityOp.CREATE);
    Collection<Tag> tags = new ArrayList<>();
    //persistence.getEntityManager().merge(lineaFactura);
    for (int i = 0; i < amount; ++i) {

        Tag tag = metadata.create(Tag.class);

        tag.setLineaFactura(lineaFactura);
        tag.setEtiqueta(uniqueNumbers.getNextNumber("etiqueta"));
        persistence.getEntityManager().merge(tag);

        tags.add(tag);
    }
    return tags;
}

Invoice:

public class Factura extends StandardEntity {
    private static final long serialVersionUID = 3628890459271116990L;

    @Column(name = "NUMERO", nullable = false)
    protected Integer numero;

    @Column(name = "PROVEDOR")
    protected String provedor;


    @Composition
    @OneToMany(mappedBy = "factura")
    @OnDelete(DeletePolicy.CASCADE)
    protected Set<LineaFactura> lineaFactura;

InvoiceLine:

public class LineaFactura extends StandardEntity {
    private static final long serialVersionUID = 7276248750060273598L;

    @Composition
    @OnDelete(DeletePolicy.CASCADE)
    @OneToMany(mappedBy = "lineaFactura")
    protected Set<Tag> tags;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ARTICULO_ID")
    protected Articulo articulo;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "FACTURA_ID")
    protected Factura factura;

And Tag:


public class Tag extends StandardEntity {
    private static final long serialVersionUID = -2637205787194250262L;

    @ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.PERSIST)
    @JoinColumn(name = "LINEA_FACTURA_ID")
    protected LineaFactura lineaFactura;

    @Column(name = "ETIQUETA")
    protected Long etiqueta;

OK : WindowAction Ok button.
Then:
I Edit a Invoice, and I make a new InvoiceLine, select one article (by default quantity = 1 and Price article.price) and press OK of InvoiceLine and then OK of invoice.
If I enter to the invoice then to the invoice line and press “Create Tags” button, tags are created and all works right;

But, if I create a new InvoiceLine and push “Create Tags” button (in this point, like before tags are created normally) without saving InvoiceLine previously, when i press OK of InvoiceEdit screen it said:

SQLIntegrityConstraintViolationException: violación del restricción de integridad: violación de índice o clave única; SYS_PK_10332 table: SUBVENCIONES_LINE_INVOICE

I tried different CascadeTypes on my annotations and many other things wihtout success.

Thanks.

1.- Commenting “persistence.getEntityManager().merge(tag);” of the ServiceTagBen.

2.- Add Cascade option to tags attribute.


@Composition
@OnDelete(DeletePolicy.CASCADE)
@OneToMany(cascade = CascadeType.PERSIST,mappedBy = "lineaFactura")
protected Set<Tag> tags;

Its necessary restart the server to changes take effect.

SQLIntegrityConstraintViolationException was produced cause I merged a item (generating a managed Item with its Uuid), and after, I persisted the same item again with the OK button then cascade persist option causes the unique Uuid restriction violation. It is important to say that in the problem definition, tags attribute of the InvoiceLine probably was defined as Cascade persist but I not recompiled the server.

Hi Ismael,

Let me suggest another solution.
You are using composition of entities (InvoiceLines belong to Invoice, Tags belong to InvoiceLine) by annotating reference attributes with @Composition. It means that if you build the proper structure of datasources in the screen, you are able to save the whole 2-level composition in one transaction when saving Invoice. But when you call the service and save Tags independently, you break the rule - tags and InvoiceLines are saved regardless of whether a user pressed OK or Cancel in the top-level Invoice editor. Moreover, I suppose you cannot add tags to a new Invoice because InvoiceLine cannot refer to a non-existent in the database row.
I think your task can be accomplished in a pure CUBA in-memory composition without any CASCADE options on the ORM level. This example shows how to do it.

Thank you very much.
Don’t knew the correct approach.
“Here, the meetingPointsDs datasource is not associated with any visual components, however it is needed for correct operation of joint editing of the composition.”