Bug? datamanger remove rows (with CompKey) using savecontext

Hi,
I want to hard delete multiple rows using the SaveContext.
Inserts work fine,
but removing not.
I tried multiple ways, using jmix 1.4…

For me it looks like, that there is an issue when using embeddedIDs.
With only a single PK in the table it works,
but having multiple columns defined for the PK.
it does not work.

Here is one example with an entity with combined keys:
> TbluaUpdDistrstockStockJmix tbluaUpdDistrstockStockJmix = metadata.create(TbluaUpdDistrstockStockJmix.class);

    tbluaUpdDistrstockStockJmix.getId().setDaykey(daykey);
    tbluaUpdDistrstockStockJmix.getId().setWarehousecode(warehousecode);
    tbluaUpdDistrstockStockJmix.getId().setProductcode(productcode);
    tbluaUpdDistrstockStockJmix.getId().setUpdDate(upddate);
    tbluaUpdDistrstockStockJmix.setDatename(datename);
    tbluaUpdDistrstockStockJmix.setMonthkey(monthkey);
    tbluaUpdDistrstockStockJmix.setStockNiv(stockniv);
    tbluaUpdDistrstockStockJmix.setStockQty(stockqty);

    //saveContext.saving(tbluaUpdDistrstockStockJmix);
    deleteContext.removing(tbluaUpdDistrstockStockJmix).setHint(PersistenceHints.SOFT_DELETION, false);

And then using datamanager.save(deleteContext)
or datamanger.remove(deleteContext)
nothing works.

Any help would be great.
Thx
Roland

Hi
In the end, did you also add the following line of code to execute the deleteContext?

unconstrainedDataManager.remove(deleteContext);

Hi,
I tried the unconstrained one too.
But only get this error when I do a .remove(deleteContext),
I get the error:
MetaClass not found for class io.jmix.core.SaveContext

When I use .save(deleteContext) I get this error:
Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.7.9.6-jmix): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [daykey] of class [com.jnj.uadwh.entity.key.TbluaUpdDistrstockStockJmixCompKey] is mapped to a primary key column in the database. Updates are not allowed.

the issue is caused by the composite key…
when I use a single PK in the table it works…
any idea how to use the datamanger remove with composite keys???

I’m not sure but you can try the following approach to remove:

Order createOrderWithCustomer() {
    Customer customer = dataManager.create(Customer.class);
    customer.setName("Alice");

    Order order = dataManager.create(Order.class);
    order.setCustomer(customer);

    EntitySet savedEntities = dataManager.save(order, customer);

    return savedEntities.get(order);
}

thx, but I do not understand how that could work in my case…
I have only 1 table in the DB which has 4 columns in the PK

and in JMIX entity class it looks like this:

@DdlGeneration(value = DdlGeneration.DbScriptGenerationMode.DISABLED)
@JmixEntity
@Store(name = “uadwhl0”)
@Table(name = “TBLUA_UPD_DISTRSTOCK_STOCK”)
@Entity(name = “uadwh_TbluaUpdDistrstockStock”)
public class TbluaUpdDistrstockStock {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = “daykey”, column = @Column(name = “DAYKEY”)),
@AttributeOverride(name = “warehousecode”, column = @Column(name = “WAREHOUSECODE”)),
@AttributeOverride(name = “productcode”, column = @Column(name = “PRODUCTCODE”)),
@AttributeOverride(name = “updDate”, column = @Column(name = “UPD_DATE”))
})
private TbluaUpdDistrstockStockCompKey id;

If I do a remove in a groupTable, it works,
but cannot see how to do it in the coding.

I forgot to mention: the deletion of multiple rows should be done in a background process.
Doing the same coding with saveContext.saving( works fine, new rows get created.
But doing the deleteContext.removing( it does not work.
When I only have a single PK and an entity class like this:

public class User implements JmixUserDetails, HasTimeZone {

@Id
@Column(name = "ID")

it works…

I also tried this:

    TbluaUpdDistrstockStockJmix tbluaUpdDistrstockStockJmix = dataManager.create(TbluaUpdDistrstockStockJmix.class);
    TbluaUpdDistrstockStockJmixCompKey compKey = dataManager.create(TbluaUpdDistrstockStockJmixCompKey.class);
    compKey.setDaykey(daykey);
    compKey.setWarehousecode(warehousecode);
    compKey.setProductcode(productcode);
    compKey.setUpdDate(upddate);
    tbluaUpdDistrstockStockJmix.setId(compKey);

    tbluaUpdDistrstockStockJmix.setDatename(datename);
    tbluaUpdDistrstockStockJmix.setMonthkey(monthkey);
    tbluaUpdDistrstockStockJmix.setStockNiv(stockniv);
    tbluaUpdDistrstockStockJmix.setStockQty(stockqty);
    saveContext.saving(tbluaUpdDistrstockStockJmix);
    deleteContext.removing(tbluaUpdDistrstockStockJmix).setHint(PersistenceHints.SOFT_DELETION, false);

but again getting this error (but only when using the embeddedId…)

Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.7.9.6-jmix): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [daykey] of class [com.jnj.uadwh.entity.key.TbluaUpdDistrstockStockJmixCompKey] is mapped to a primary key column in the database. Updates are not allowed.

May be someone from Jmix team can help

1 Like

and one more additional information:

I tried out multiple ways to get it running…
the only workaround I could found, was in the UI:
I noticed that all instances that got loaded in the groupTable,
I could select and paste them as a set into the saveContext.removing()
When I do a dataManager.save() then, it works.

But if I try to add the rows to the dc for that table,
then selectAll and try to remove them,
it does not work.
Everytime I get the same error again then:

ValidationException:
Exception Description: The attribute [daykey] of class [com.jnj.uadwh.entity.key.TbluaUpdDistrstockStockJmixCompKey] is mapped to a primary key column in the database. Updates are not allowed.

Hello,
I’ve tried to create a simple entity with a composite key and remove it in different ways:

  1. Like you describe:
        CKey removeKey = dataManager.create(CKey.class);
        removeKey.setPart1("test1");
        removeKey.setPart2(2);

        Assertions.assertTrue(dataManager.load(CKeyEntity.class).id(removeKey).optional().isPresent());

        CKeyEntity toRemove = dataManager.create(CKeyEntity.class);
        toRemove.setId(removeKey);
        dataManager.remove(toRemove);

        Assertions.assertFalse(dataManager.load(CKeyEntity.class).id(removeKey).optional().isPresent());

  1. By loading through data manager:
        CKey removeKey = dataManager.create(CKey.class);
        removeKey.setPart1("test1");
        removeKey.setPart2(2);

        CKeyEntity loaded = dataManager.load(CKeyEntity.class).id(removeKey).one();
        dataManager.remove(loaded);
  1. By finding through entity manager:
   @Transactional
    void testCompositeKeyEntityRemoving() {
        CKey removeKey = dataManager.create(CKey.class);
        removeKey.setPart1("test1");
        removeKey.setPart2(2);

        CKeyEntity found = em.find(CKeyEntity.class, removeKey);
        dataManager.remove(found);
    }

And no such problem occurs for me. You can try it in the test project (see CkeydelsamplApplicationTests.java):
ckeydelsampl.zip (167.3 KB)

Can you, please, provide a minimal example (or, better, a simple project) to reproduce your issue?

Could it be some problem with transactions or not properly loaded/reloaded entities? Approaches (2) and (3) may help in such cases.

Regards,
Dmitry

Hi Dimitri,

thx for that.
I can check on Monday and will then also send you a little test app if still needed.

Best Regards
Roland Walde

I would appreciate it if you could check it and provide a little test app in case of the problem still occurs, but there is no rush :slightly_smiling_face:

do not know how to do it with hsqldb… we have a MSSQL where multiple tables have combined PKs defined.
I added 2 classes which look similar to those we have for those tables with combined PKs.
If you need more information, I would need to create a new project based on SQL Server…
But I do not have the time for that this week.
Actually we got a workaround using JDBCTemplate, but would like to use the saveContext.

In our app the definition looks like this:
for the CompKey

package com.company.ckeydelsampl.entity.key;

import org.springframework.data.util.ProxyUtils;

import javax.persistence.*;
import java.util.Objects;

public class TestTableCompKey {

@Column(name = "PK1", nullable = false, unique = true)
private String PK1;

@Column(name = "PK2", nullable = false, unique = true)
private String PK2;

@Column(name = "PK3", nullable = false, unique = true)
private String PK3;

public String getPK1() {
    return PK1;
}

public void setPK1(String PK1) {
    this.PK1 = PK1;
}

public String getPK2() {
    return PK2;
}

public void setPK2(String PK2) {
    this.PK2 = PK2;
}

public String getPK3() {
    return PK3;
}

public void setPK3(String PK3) {
    this.PK3 = PK3;
}

@Override
public int hashCode() {
    return Objects.hash(PK1,PK2,PK3);
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || ProxyUtils.getUserClass(this) != ProxyUtils.getUserClass(o)) return false;
    TestTableCompKey entity = (TestTableCompKey) o;
    return Objects.equals(this.PK1, entity.PK1) &&
            Objects.equals(this.PK2, entity.PK2) &&
            Objects.equals(this.PK3, entity.PK3);
}

}

/*
package com.jnj.uadwh.entity.key;

@JmixEntity(name = “uadwh_TbluaUpdDistrstockStockJmixCompKey”)
@Embeddable
public class TbluaUpdDistrstockStockJmixCompKey {
@Column(name = “DAYKEY”, nullable = false, unique = true, precision = 38, scale = 0)
private BigDecimal daykey;

@Column(name = "PRODUCTCODE", nullable = false, unique = true, length = 20)
private String productcode;

@Column(name = "UPD_DATE", nullable = false, unique = true)
@Temporal(TemporalType.TIMESTAMP)
private Date updDate;

@Column(name = "WAREHOUSECODE", nullable = false, unique = true, length = 20)
private String warehousecode;

public String getWarehousecode() {
    return warehousecode;
}

public void setWarehousecode(String warehousecode) {
    this.warehousecode = warehousecode;
}

public Date getUpdDate() {
    return updDate;
}

public void setUpdDate(Date updDate) {
    this.updDate = updDate;
}

public String getProductcode() {
    return productcode;
}

public void setProductcode(String productcode) {
    this.productcode = productcode;
}

public BigDecimal getDaykey() {
    return daykey;
}

public void setDaykey(BigDecimal daykey) {
    this.daykey = daykey;
}

@Override
public int hashCode() {
    return Objects.hash(productcode, daykey, warehousecode, updDate);
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || ProxyUtils.getUserClass(this) != ProxyUtils.getUserClass(o)) return false;
    TbluaUpdDistrstockStockJmixCompKey entity = (TbluaUpdDistrstockStockJmixCompKey) o;
    return Objects.equals(this.productcode, entity.productcode) &&
            Objects.equals(this.daykey, entity.daykey) &&
            Objects.equals(this.warehousecode, entity.warehousecode) &&
            Objects.equals(this.updDate, entity.updDate);
}

}

and for the entity.class

package com.company.ckeydelsampl.entity;

import com.company.ckeydelsampl.entity.key.TestTableCompKey;
import io.jmix.core.metamodel.annotation.JmixEntity;

import javax.persistence.*;

@JmixEntity
@Table(name = “TEST_TABLE”)
@Entity
public class TestTable {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = “PK1”, column = @Column(name = “PK1”)),
@AttributeOverride(name = “PK2”, column = @Column(name = “PK2”)),
@AttributeOverride(name = “PK3”, column = @Column(name = “PK3”)),
})
private TestTableCompKey id;

@Column(name = "COL1")
private String col1;

@Column(name = "COL2")
private String col2;


public String getCol2() {
    return col2;
}

public void setCol2(String col2) {
    this.col2 = col2;
}

public String getCol1() {
    return col1;
}

public void setCol1(String col1) {
    this.col1 = col1;
}


public TestTableCompKey getId() {
    return id;
}

public void setId(TestTableCompKey id) {
    this.id = id;
}

}