#1952 - Entity bean with @Id and ONLY @WhenCreated treated as reference bean - not inserted

This commit is contained in:
rob bygrave
2020-02-21 00:14:23 +13:00
parent a23d9f7db8
commit e4390ed8a2
8 changed files with 136 additions and 10 deletions
@@ -376,7 +376,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private final BeanProperty[] propertiesGenInsert;
private final BeanProperty[] propertiesGenUpdate;
private final List<BeanProperty[]> propertiesUnique = new ArrayList<>();
private final boolean idOnlyReference;
private BeanNaturalKey beanNaturalKey;
/**
@@ -512,7 +512,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.propertiesOneImported = listHelper.getOneImported();
this.propertiesOneImportedSave = listHelper.getOneImportedSave();
this.propertiesOneImportedDelete = listHelper.getOneImportedDelete();
this.propertiesMany = listHelper.getMany();
this.propertiesNonMany = listHelper.getNonMany();
this.propertiesAggregate = listHelper.getAggregates();
@@ -521,6 +520,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.propertiesManyToMany = listHelper.getManyToMany();
this.propertiesGenInsert = listHelper.getGeneratedInsert();
this.propertiesGenUpdate = listHelper.getGeneratedUpdate();
this.idOnlyReference = isIdOnlyReference(propertiesBaseScalar);
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
@@ -568,6 +568,19 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
}
/**
* Return true if the bean should be treated as a reference bean when it only has its id populated.
* To be true it has other scalar properties that are not generated on insert.
*/
private boolean isIdOnlyReference(BeanProperty[] baseScalar) {
for (BeanProperty beanProperty : baseScalar) {
if (!beanProperty.isGeneratedOnInsert()) {
return true;
}
}
return false;
}
/**
* Derive an array of property positions for properties that are initialised in the constructor.
* These properties need to be unloaded when populating beans for queries.
@@ -1809,7 +1822,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Find a property annotated with @WhenCreated or @CreatedTimestamp.
*/
private BeanProperty findWhenCreatedProperty() {
for (BeanProperty aPropertiesBaseScalar : propertiesBaseScalar) {
if (aPropertiesBaseScalar.isGeneratedWhenCreated()) {
return aPropertiesBaseScalar;
@@ -3301,11 +3313,11 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
public boolean isReference(EntityBeanIntercept ebi) {
return ebi.isReference() || hasIdPropertyOnly(ebi);
return ebi.isReference() || referenceIdPropertyOnly(ebi);
}
boolean hasIdPropertyOnly(EntityBeanIntercept ebi) {
return propertiesBaseScalar.length > 0 && ebi.hasIdOnly(idPropertyIndex);
boolean referenceIdPropertyOnly(EntityBeanIntercept ebi) {
return idOnlyReference && ebi.hasIdOnly(idPropertyIndex);
}
public boolean isIdLoaded(EntityBeanIntercept ebi) {
@@ -1160,6 +1160,10 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
return isVersion() || (generatedProperty != null && generatedProperty.isDDLNotNullable());
}
boolean isGeneratedOnInsert() {
return generatedProperty != null && generatedProperty.includeInInsert();
}
/**
* Return true if this is a generated property mapping to @WhenCreated or @CreatedTimestamp.
*/
@@ -8,7 +8,7 @@ import java.util.Date;
/**
* Used to generate a (java.util.Date) timestamp when a bean is inserted.
*/
public class GeneratedInsertDate implements GeneratedProperty {
public class GeneratedInsertDate implements GeneratedProperty, GeneratedWhenCreated {
/**
* Return the current time as a Timestamp.
@@ -11,6 +11,8 @@ import org.tests.model.basic.Order;
import org.tests.model.composite.RCustomer;
import org.tests.model.composite.RCustomerKey;
import org.junit.Test;
import org.tests.model.embedded.UserInterestLive;
import org.tests.model.embedded.UserInterestLiveKey;
import java.sql.Timestamp;
import java.util.Map;
@@ -56,13 +58,21 @@ public class TestBeanDescriptorHasIdProperty extends BaseTestCase {
Customer order = new Customer();
EntityBeanIntercept ebi = getIntercept(order);
assertFalse(beanDescriptor.hasIdPropertyOnly(ebi));
assertFalse(beanDescriptor.referenceIdPropertyOnly(ebi));
order.setId(23);
assertTrue(beanDescriptor.hasIdPropertyOnly(ebi));
assertTrue(beanDescriptor.referenceIdPropertyOnly(ebi));
order.setName("custName");
assertFalse(beanDescriptor.hasIdPropertyOnly(ebi));
assertFalse(beanDescriptor.referenceIdPropertyOnly(ebi));
}
@Test
public void isReference_withGeneratedOnInsertOnlyProperty_expect_false() {
BeanDescriptor<UserInterestLive> descriptor = spiServer.getBeanDescriptor(UserInterestLive.class);
UserInterestLive bean = new UserInterestLive(new UserInterestLiveKey(1L, 2L));
EntityBeanIntercept ebi = getIntercept(bean);
assertFalse(descriptor.referenceIdPropertyOnly(ebi));
}
@Test
@@ -0,0 +1,17 @@
package io.ebeaninternal.server.deploy.generatedproperty;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class GeneratedInsertJavaTimeTest {
@Test
public void test_generatedOnInsert() {
GeneratedProperty gen = new GeneratedInsertJavaTime.InstantDT();
assertTrue(GeneratedWhenCreated.class.isInstance(gen));
assertTrue(gen instanceof GeneratedWhenCreated);
}
}
@@ -0,0 +1,19 @@
package org.tests.model.embedded;
import io.ebean.DB;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestEmbeddedEqualsWhenCreated {
@Test
public void test() {
UserInterestLive bean = new UserInterestLive(new UserInterestLiveKey(1L, 2L));
bean.save();
final UserInterestLive found = DB.find(UserInterestLive.class, bean.getKey());
assertEquals(found, bean); // <- failed as bean not inserted
}
}
@@ -0,0 +1,34 @@
package org.tests.model.embedded;
import io.ebean.Model;
import io.ebean.annotation.CreatedTimestamp;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import java.util.Date;
@Entity
public class UserInterestLive extends Model {
@EmbeddedId
private final UserInterestLiveKey key;
@CreatedTimestamp
private Date createdAt;
public UserInterestLive(UserInterestLiveKey key) {
this.key = key;
}
public UserInterestLiveKey getKey() {
return key;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
}
@@ -0,0 +1,30 @@
package org.tests.model.embedded;
import javax.persistence.Embeddable;
import java.util.Objects;
@Embeddable
public class UserInterestLiveKey {
private long userId;
private long liveId;
public UserInterestLiveKey(long userId, long liveId) {
this.userId = userId;
this.liveId = liveId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserInterestLiveKey that = (UserInterestLiveKey) o;
return userId == that.userId &&
liveId == that.liveId;
}
@Override
public int hashCode() {
return Objects.hash(userId, liveId);
}
}