diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 0635d5e06..d50f67423 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -2875,8 +2875,8 @@ public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { final EntityBeanIntercept ebi = bean._ebean_getIntercept(); for (BeanPropertyAssocMany many : propertiesManySave) { if (ebi.isLoadedProperty(many.propertyIndex())) { - final BeanCollection value = (BeanCollection) many.getValue(bean); - if (value != null && value.hasModifications()) { + final Object value = many.getValue(bean); + if (value instanceof BeanCollection && ((BeanCollection)value).hasModifications() || value != null) { return true; } } diff --git a/ebean-test/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-test/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index ed0cfb175..60db7b27b 100644 --- a/ebean-test/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-test/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -13,6 +13,7 @@ import org.tests.model.basic.EBasicVer; import org.tests.model.basic.Order; import org.tests.model.basic.OrderShipment; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -176,6 +177,38 @@ public class TestTransparentPersist extends BaseTestCase { DB.delete(Customer.class, c0.getId()); } + @Test + public void insertWithPersistCascadeInsert() { + + // setup data + Customer c0 = new Customer(); + c0.setName("firstCust"); + DB.save(c0); + + Integer orderId; + try (Transaction transaction = DB.beginTransaction()) { + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature + Order order = new Order(); + order.setStatus(Order.Status.NEW); + order.setCustomer(c0); + order.setShipments(new ArrayList<>()); + DB.insert(order); + orderId = order.getId(); + // cascade persist will insert this Shipment (even though it isn't in the persistence context) + OrderShipment osh0 = new OrderShipment(); + order.addShipment(osh0); + transaction.commit(); + } + + Order checkOrder = DB.find(Order.class, orderId); + + assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.NEW); + assertThat(checkOrder.getShipments().size()).isEqualTo(1); + + DB.delete(checkOrder); + DB.delete(Customer.class, c0.getId()); + } + @Test public void updateReferenceOnlyWithPersistCascade_Insert_andUpdateForeignKey() { diff --git a/tests/pom.xml b/tests/pom.xml index 2c79d71fa..28e238922 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -17,7 +17,7 @@ test-java16 + test-kotlin - diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml new file mode 100644 index 000000000..87ef28f4a --- /dev/null +++ b/tests/test-kotlin/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + org.avaje + java11-oss + 2.3 + + + kotlin test + Kotlin specific tests + test-kotlin + 1.0 + + + 11 + 11 + + 12.11.5 + 1.5.31 + 2.12.1 + + + + + io.avaje + junit + 1.0 + test + + + + io.ebean + ebean-test + 12.11.6-SNAPSHOT + test + + + + io.ebean + ebean-core + 12.11.6-SNAPSHOT + test + + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + test + + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + + + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 11 + + + + test-compile + + test-compile + + + + + + io.ebean + ebean-maven-plugin + ${ebean-maven-plugin.version} + + + test + process-test-classes + + debug=1 + + + testEnhance + + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + true + + + + + + diff --git a/tests/test-kotlin/src/test/kotlin/io/ebean/test/kotlin/TransparentPersistenceTest.kt b/tests/test-kotlin/src/test/kotlin/io/ebean/test/kotlin/TransparentPersistenceTest.kt new file mode 100644 index 000000000..06497c458 --- /dev/null +++ b/tests/test-kotlin/src/test/kotlin/io/ebean/test/kotlin/TransparentPersistenceTest.kt @@ -0,0 +1,41 @@ +package io.ebean.test.kotlin + +import io.ebean.DB +import org.assertj.core.api.Assertions.assertThat +import org.example.order.Customer +import org.example.order.Order +import org.example.order.OrderItem +import org.junit.jupiter.api.Test +import java.math.BigDecimal +import kotlin.test.assertNotNull + +class TransparentPersistenceTest { + + @Test + fun `insert with cascade insert`() { + // setup data + + // setup data + val c0 = Customer("Customer 0") + DB.save(c0) + + var orderId: Long + DB.beginTransaction().use { transaction -> + transaction.setAutoPersistUpdates(true) // EXPERIMENTAL feature + val order = Order(c0) + DB.insert(order) + orderId = order.id + // cascade persist will insert this OrderItem (even though it isn't in the persistence context) + order.items.add(OrderItem(order, "item 0", BigDecimal.TEN)) + transaction.commit() + } + + val checkOrder = DB.find(Order::class.java, orderId) + + assertNotNull(checkOrder) + assertThat(checkOrder.items.size).isEqualTo(1) + + DB.delete(checkOrder) + DB.delete(c0) + } +} diff --git a/tests/test-kotlin/src/test/kotlin/org/example/order/Customer.kt b/tests/test-kotlin/src/test/kotlin/org/example/order/Customer.kt new file mode 100644 index 000000000..72c2795af --- /dev/null +++ b/tests/test-kotlin/src/test/kotlin/org/example/order/Customer.kt @@ -0,0 +1,17 @@ +package org.example.order + +import javax.persistence.Entity +import javax.persistence.Id +import javax.persistence.Version + +@Entity +class Customer( + name: String, +) { + @Id + var id: Int = 0 + val name: String = name + + @Version + var version: Long = 0 +} diff --git a/tests/test-kotlin/src/test/kotlin/org/example/order/Order.kt b/tests/test-kotlin/src/test/kotlin/org/example/order/Order.kt new file mode 100644 index 000000000..a5e87f9d9 --- /dev/null +++ b/tests/test-kotlin/src/test/kotlin/org/example/order/Order.kt @@ -0,0 +1,27 @@ +package org.example.order + +import javax.persistence.CascadeType +import javax.persistence.Entity +import javax.persistence.Id +import javax.persistence.ManyToOne +import javax.persistence.OneToMany +import javax.persistence.Table +import javax.persistence.Version + +@Entity +@Table(name = "t_order") +class Order( + customer: Customer, +) { + @Id + val id: Long = 0 + + @ManyToOne + val customer: Customer = customer + + @OneToMany(mappedBy = "order", cascade = [CascadeType.ALL], orphanRemoval = true) + val items: MutableList = mutableListOf() + + @Version + val version: Long = 0 +} diff --git a/tests/test-kotlin/src/test/kotlin/org/example/order/OrderItem.kt b/tests/test-kotlin/src/test/kotlin/org/example/order/OrderItem.kt new file mode 100644 index 000000000..6a7e123ec --- /dev/null +++ b/tests/test-kotlin/src/test/kotlin/org/example/order/OrderItem.kt @@ -0,0 +1,29 @@ +package org.example.order + +import java.math.BigDecimal +import javax.persistence.Entity +import javax.persistence.Id +import javax.persistence.ManyToOne + +@Entity +class OrderItem( + order: Order, + name: String, + price: BigDecimal, + amount: Int = 1, + description: String? = null, +) { + @Id + val id: Long = 0 + + @ManyToOne + val order: Order = order + + val name: String = name + + val description: String? = description + + val amount: Int = amount + + val price: BigDecimal = price +} diff --git a/tests/test-kotlin/src/test/resources/application-test.yaml b/tests/test-kotlin/src/test/resources/application-test.yaml new file mode 100644 index 000000000..029b11023 --- /dev/null +++ b/tests/test-kotlin/src/test/resources/application-test.yaml @@ -0,0 +1,6 @@ +ebean: + test: + platform: h2 + ddlMode: dropCreate + dbName: foo + diff --git a/tests/test-kotlin/src/test/resources/logback-test.xml b/tests/test-kotlin/src/test/resources/logback-test.xml new file mode 100644 index 000000000..ce7ad5968 --- /dev/null +++ b/tests/test-kotlin/src/test/resources/logback-test.xml @@ -0,0 +1,22 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + +