mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
The issue was due to the loaded status not being recursively set on embedded beans after inserts. The test case invoked lazy loading due to that which lead to the issue.
767 lines
22 KiB
Java
767 lines
22 KiB
Java
package io.ebeaninternal.server.deploy;
|
|
|
|
import io.ebean.EbeanServer;
|
|
import io.ebean.Query;
|
|
import io.ebean.SqlUpdate;
|
|
import io.ebean.Transaction;
|
|
import io.ebean.ValuePair;
|
|
import io.ebean.bean.EntityBean;
|
|
import io.ebean.bean.PersistenceContext;
|
|
import io.ebeaninternal.server.cache.CacheChangeSet;
|
|
import io.ebeaninternal.server.cache.CachedBeanData;
|
|
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
|
import io.ebeaninternal.server.deploy.id.ImportedId;
|
|
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
|
import io.ebeaninternal.server.el.ElPropertyChainBuilder;
|
|
import io.ebeaninternal.server.el.ElPropertyValue;
|
|
import io.ebeaninternal.server.query.SplitName;
|
|
import io.ebeaninternal.server.query.SqlBeanLoad;
|
|
import io.ebeaninternal.server.query.SqlJoinType;
|
|
import io.ebeaninternal.server.text.json.ReadJson;
|
|
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
|
|
|
import javax.persistence.PersistenceException;
|
|
import java.io.IOException;
|
|
import java.sql.SQLException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Property mapped to a joined bean.
|
|
*/
|
|
public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
|
|
|
private final boolean oneToOne;
|
|
|
|
private final boolean oneToOneExported;
|
|
|
|
private final boolean importedPrimaryKey;
|
|
|
|
private AssocOneHelp localHelp;
|
|
|
|
protected final BeanProperty[] embeddedProps;
|
|
|
|
private final HashMap<String, BeanProperty> embeddedPropsMap;
|
|
|
|
/**
|
|
* The information for Imported foreign Keys.
|
|
*/
|
|
protected ImportedId importedId;
|
|
|
|
private String deleteByParentIdSql;
|
|
private String deleteByParentIdInSql;
|
|
|
|
private BeanPropertyAssocMany<?> relationshipProperty;
|
|
|
|
/**
|
|
* Create based on deploy information of an EmbeddedId.
|
|
*/
|
|
public BeanPropertyAssocOne(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<T> deploy) {
|
|
this(owner, null, deploy);
|
|
}
|
|
|
|
/**
|
|
* Create the property.
|
|
*/
|
|
public BeanPropertyAssocOne(BeanDescriptorMap owner, BeanDescriptor<?> descriptor,
|
|
DeployBeanPropertyAssocOne<T> deploy) {
|
|
|
|
super(descriptor, deploy);
|
|
|
|
importedPrimaryKey = deploy.isImportedPrimaryKey();
|
|
oneToOne = deploy.isOneToOne();
|
|
oneToOneExported = deploy.isOneToOneExported();
|
|
|
|
if (embedded) {
|
|
// Overriding of the columns and use table alias of owning BeanDescriptor
|
|
BeanEmbeddedMeta overrideMeta = BeanEmbeddedMetaFactory.create(owner, deploy);
|
|
embeddedProps = overrideMeta.getProperties();
|
|
embeddedPropsMap = new HashMap<>();
|
|
for (BeanProperty embeddedProp : embeddedProps) {
|
|
embeddedPropsMap.put(embeddedProp.getName(), embeddedProp);
|
|
}
|
|
|
|
} else {
|
|
embeddedProps = null;
|
|
embeddedPropsMap = null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void initialise() {
|
|
super.initialise();
|
|
localHelp = createHelp(embedded, oneToOneExported);
|
|
|
|
if (!isTransient) {
|
|
//noinspection StatementWithEmptyBody
|
|
if (embedded) {
|
|
// no imported or exported information
|
|
} else if (!oneToOneExported) {
|
|
importedId = createImportedId(this, targetDescriptor, tableJoin);
|
|
if (importedId.isScalar()) {
|
|
// limit JoinColumn mapping to the @Id / primary key
|
|
TableJoinColumn[] columns = tableJoin.columns();
|
|
String foreignJoinColumn = columns[0].getForeignDbColumn();
|
|
String foreignIdColumn = targetDescriptor.getIdProperty().getDbColumn();
|
|
if (!foreignJoinColumn.equalsIgnoreCase(foreignIdColumn)) {
|
|
throw new PersistenceException("Mapping limitation - @JoinColumn on " + getFullBeanName() + " needs to map to a primary key as per Issue #529 "
|
|
+ " - joining to " + foreignJoinColumn + " and not " + foreignIdColumn);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
exportedProperties = createExported();
|
|
|
|
String delStmt = "delete from " + targetDescriptor.getBaseTable() + " where ";
|
|
deleteByParentIdSql = delStmt + deriveWhereParentIdSql(false);
|
|
deleteByParentIdInSql = delStmt + deriveWhereParentIdSql(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the property value as an entity bean.
|
|
*/
|
|
public EntityBean getValueAsEntityBean(EntityBean owner) {
|
|
return (EntityBean) getValue(owner);
|
|
}
|
|
|
|
void setRelationshipProperty(BeanPropertyAssocMany<?> relationshipProperty) {
|
|
this.relationshipProperty = relationshipProperty;
|
|
}
|
|
|
|
/**
|
|
* Return true if this relationship needs to maintain/update L2 cache.
|
|
*/
|
|
boolean isCacheNotify() {
|
|
return targetDescriptor.isBeanCaching() && relationshipProperty != null;
|
|
}
|
|
|
|
/**
|
|
* Clear the L2 relationship cache for this property.
|
|
*/
|
|
void cacheClear() {
|
|
if (isCacheNotify()) {
|
|
targetDescriptor.cacheManyPropClear(relationshipProperty.getName());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear part of the L2 relationship cache for this property.
|
|
*/
|
|
void cacheDelete(boolean clear, EntityBean bean, CacheChangeSet changeSet) {
|
|
|
|
if (isCacheNotify()) {
|
|
if (clear) {
|
|
changeSet.addManyClear(targetDescriptor, relationshipProperty.getName());
|
|
} else {
|
|
Object assocBean = getValue(bean);
|
|
if (assocBean != null) {
|
|
Object parentId = targetDescriptor.getId((EntityBean) assocBean);
|
|
if (parentId != null) {
|
|
changeSet.addManyRemove(targetDescriptor, relationshipProperty.getName(), parentId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
|
|
|
if (embedded) {
|
|
BeanProperty embProp = embeddedPropsMap.get(remainder);
|
|
if (embProp == null) {
|
|
String msg = "Embedded Property " + remainder + " not found in " + getFullBeanName();
|
|
throw new PersistenceException(msg);
|
|
}
|
|
if (chain == null) {
|
|
chain = new ElPropertyChainBuilder(true, propName);
|
|
}
|
|
chain.add(this);
|
|
chain.setEmbedded(true);
|
|
|
|
return chain.add(embProp).build();
|
|
}
|
|
|
|
return createElPropertyValue(propName, remainder, chain, propertyDeploy);
|
|
}
|
|
|
|
@Override
|
|
public String getElPlaceholder(boolean encrypted) {
|
|
return encrypted ? elPlaceHolderEncrypted : elPlaceHolder;
|
|
}
|
|
|
|
public SqlUpdate deleteByParentId(Object parentId, List<Object> parentIdist) {
|
|
if (parentId != null) {
|
|
return deleteByParentId(parentId);
|
|
} else {
|
|
return deleteByParentIdList(parentIdist);
|
|
}
|
|
}
|
|
|
|
private SqlUpdate deleteByParentIdList(List<Object> parentIdist) {
|
|
|
|
StringBuilder sb = new StringBuilder(100);
|
|
sb.append(deleteByParentIdInSql);
|
|
|
|
String inClause = targetIdBinder.getIdInValueExpr(parentIdist.size());
|
|
sb.append(inClause);
|
|
|
|
DefaultSqlUpdate delete = new DefaultSqlUpdate(sb.toString());
|
|
for (Object aParentIdist : parentIdist) {
|
|
targetIdBinder.bindId(delete, aParentIdist);
|
|
}
|
|
|
|
return delete;
|
|
}
|
|
|
|
private SqlUpdate deleteByParentId(Object parentId) {
|
|
|
|
DefaultSqlUpdate delete = new DefaultSqlUpdate(deleteByParentIdSql);
|
|
if (exportedProperties.length == 1) {
|
|
delete.addParameter(parentId);
|
|
} else {
|
|
targetDescriptor.getIdBinder().bindId(delete, parentId);
|
|
}
|
|
return delete;
|
|
}
|
|
|
|
public List<Object> findIdsByParentId(Object parentId, List<Object> parentIdist, Transaction t) {
|
|
if (parentId != null) {
|
|
return findIdsByParentId(parentId, t);
|
|
} else {
|
|
return findIdsByParentIdList(parentIdist, t);
|
|
}
|
|
}
|
|
|
|
private List<Object> findIdsByParentId(Object parentId, Transaction t) {
|
|
|
|
String rawWhere = deriveWhereParentIdSql(false);
|
|
|
|
List<Object> bindValues = new ArrayList<>();
|
|
bindWhereParentId(bindValues, parentId);
|
|
|
|
EbeanServer server = getBeanDescriptor().getEbeanServer();
|
|
Query<?> q = server.find(getPropertyType())
|
|
.where()
|
|
.raw(rawWhere, bindValues.toArray())
|
|
.query();
|
|
|
|
return server.findIds(q, t);
|
|
}
|
|
|
|
private List<Object> findIdsByParentIdList(List<Object> parentIdList, Transaction t) {
|
|
|
|
String rawWhere = deriveWhereParentIdSql(true);
|
|
String inClause = targetIdBinder.getIdInValueExpr(parentIdList.size());
|
|
|
|
String expr = rawWhere + inClause;
|
|
|
|
List<Object> bindValues = new ArrayList<>();
|
|
for (Object aParentIdList : parentIdList) {
|
|
bindWhereParentId(bindValues, aParentIdList);
|
|
}
|
|
|
|
EbeanServer server = getBeanDescriptor().getEbeanServer();
|
|
Query<?> q = server.find(getPropertyType())
|
|
.where().raw(expr, bindValues.toArray()).query();
|
|
|
|
return server.findIds(q, t);
|
|
}
|
|
|
|
void addFkey() {
|
|
if (importedId != null) {
|
|
importedId.addFkeys(name);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void registerColumn(BeanDescriptor<?> desc, String prefix) {
|
|
if (embedded) {
|
|
for (BeanProperty prop : embeddedProps) {
|
|
prop.registerColumn(desc, SplitName.add(prefix, name));
|
|
}
|
|
} else {
|
|
if (targetIdProperty != null) {
|
|
BeanDescriptor<T> target = getTargetDescriptor();
|
|
String basePath = SplitName.add(prefix, name);
|
|
if (dbColumn != null) {
|
|
BeanProperty idProperty = target.getIdProperty();
|
|
desc.registerColumn(dbColumn, SplitName.add(basePath, idProperty.getName()));
|
|
}
|
|
|
|
desc.registerTable(target.getBaseTable(), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return meta data for the deployment of the embedded bean specific to this
|
|
* property.
|
|
*/
|
|
public BeanProperty[] getProperties() {
|
|
return embeddedProps;
|
|
}
|
|
|
|
@Override
|
|
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
|
|
|
|
prefix = SplitName.add(prefix, name);
|
|
|
|
if (!embedded) {
|
|
InheritInfo inheritInfo = targetDescriptor.getInheritInfo();
|
|
if (inheritInfo != null) {
|
|
// expect the discriminator column to be included in order
|
|
// to determine the inheritance type so we add it to the
|
|
// selectChain (so that it takes a position in the resultSet)
|
|
String discriminatorColumn = inheritInfo.getDiscriminatorColumn();
|
|
String discProperty = prefix + "." + discriminatorColumn;
|
|
selectChain.add(discProperty);
|
|
}
|
|
targetIdBinder.buildRawSqlSelectChain(prefix, selectChain);
|
|
|
|
} else {
|
|
for (BeanProperty embeddedProp : embeddedProps) {
|
|
embeddedProp.buildRawSqlSelectChain(prefix, selectChain);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
|
|
*/
|
|
public boolean isOneToOne() {
|
|
return oneToOne;
|
|
}
|
|
|
|
/**
|
|
* Return true if this is the exported side of a OneToOne.
|
|
*/
|
|
public boolean isOneToOneExported() {
|
|
return oneToOneExported;
|
|
}
|
|
|
|
/**
|
|
* If true this bean maps to the primary key.
|
|
*/
|
|
public boolean isImportedPrimaryKey() {
|
|
return importedPrimaryKey;
|
|
}
|
|
|
|
@Override
|
|
public void diff(String prefix, Map<String, ValuePair> map, EntityBean newBean, EntityBean oldBean) {
|
|
|
|
Object newEmb = (newBean == null) ? null : getValue(newBean);
|
|
Object oldEmb = (oldBean == null) ? null : getValue(oldBean);
|
|
if (newEmb == null && oldEmb == null) {
|
|
return;
|
|
}
|
|
|
|
if (embedded) {
|
|
prefix = (prefix == null) ? name : prefix + "." + name;
|
|
BeanDescriptor<T> targetDescriptor = getTargetDescriptor();
|
|
targetDescriptor.diff(prefix, map, (EntityBean) newEmb, (EntityBean) oldEmb);
|
|
|
|
} else {
|
|
// we are only interested in the Id value
|
|
newBean = (EntityBean) newEmb;
|
|
oldBean = (EntityBean) oldEmb;
|
|
|
|
BeanDescriptor<T> targetDescriptor = getTargetDescriptor();
|
|
BeanProperty idProperty = targetDescriptor.getIdProperty();
|
|
|
|
Object newId = (newBean == null) ? null : idProperty.getValue(newBean);
|
|
Object oldId = (oldBean == null) ? null : idProperty.getValue(oldBean);
|
|
if (newId != null || oldId != null) {
|
|
prefix = (prefix == null) ? name : prefix + "." + name;
|
|
idProperty.diffVal(prefix, map, newId, oldId);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Same as getPropertyType(). Return the type of the bean this property
|
|
* represents.
|
|
*/
|
|
@Override
|
|
public Class<?> getTargetType() {
|
|
return getPropertyType();
|
|
}
|
|
|
|
@Override
|
|
public Object getCacheDataValue(EntityBean bean) {
|
|
Object ap = getValue(bean);
|
|
if (ap == null) {
|
|
return null;
|
|
}
|
|
if (embedded) {
|
|
return targetDescriptor.cacheEmbeddedBeanExtract((EntityBean) ap);
|
|
} else {
|
|
return targetDescriptor.getIdProperty().getCacheDataValue((EntityBean) ap);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setCacheDataValue(EntityBean bean, Object cacheData, PersistenceContext context) {
|
|
if (cacheData == null) {
|
|
setValue(bean, null);
|
|
} else {
|
|
if (embedded) {
|
|
setValue(bean, targetDescriptor.cacheEmbeddedBeanLoad((CachedBeanData) cacheData, context));
|
|
} else {
|
|
if (cacheData instanceof String) {
|
|
cacheData = targetDescriptor.getIdProperty().scalarType.parse((String) cacheData);
|
|
}
|
|
// cacheData is the id value, maybe already in persistence context
|
|
Object assocBean = targetDescriptor.contextGet(context, cacheData);
|
|
if (assocBean == null) {
|
|
assocBean = targetDescriptor.createReference(Boolean.FALSE, false, cacheData, context);
|
|
}
|
|
setValue(bean, assocBean);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the Id values from the given bean.
|
|
*/
|
|
@Override
|
|
public Object[] getAssocIdValues(EntityBean bean) {
|
|
return targetDescriptor.getIdBinder().getIdValues(bean);
|
|
}
|
|
|
|
/**
|
|
* Return the Id expression to add to where clause etc.
|
|
*/
|
|
@Override
|
|
public String getAssocIdExpression(String prefix, String operator) {
|
|
return targetDescriptor.getIdBinder().getAssocOneIdExpr(prefix, operator);
|
|
}
|
|
|
|
/**
|
|
* Return the logical id value expression taking into account embedded id's.
|
|
*/
|
|
@Override
|
|
public String getAssocIdInValueExpr(int size) {
|
|
return targetDescriptor.getIdBinder().getIdInValueExpr(size);
|
|
}
|
|
|
|
/**
|
|
* Return the logical id in expression taking into account embedded id's.
|
|
*/
|
|
@Override
|
|
public String getAssocIdInExpr(String prefix) {
|
|
return targetDescriptor.getIdBinder().getAssocIdInExpr(prefix);
|
|
}
|
|
|
|
@Override
|
|
public boolean isAssocId() {
|
|
return !embedded;
|
|
}
|
|
|
|
@Override
|
|
public boolean isAssocProperty() {
|
|
return !embedded;
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a bean of the target type to be used as an embeddedId
|
|
* value.
|
|
*/
|
|
public Object createEmbeddedId() {
|
|
return getTargetDescriptor().createEntityBean();
|
|
}
|
|
|
|
@Override
|
|
public Object pathGetNested(Object bean) {
|
|
Object value = getValueIntercept((EntityBean) bean);
|
|
if (value == null) {
|
|
value = targetDescriptor.createEntityBean();
|
|
setValueIntercept((EntityBean) bean, value);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public ImportedId getImportedId() {
|
|
return importedId;
|
|
}
|
|
|
|
private String deriveWhereParentIdSql(boolean inClause) {
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
for (int i = 0; i < exportedProperties.length; i++) {
|
|
String fkColumn = exportedProperties[i].getForeignDbColumn();
|
|
if (i > 0) {
|
|
String s = inClause ? "," : " and ";
|
|
sb.append(s);
|
|
}
|
|
sb.append(fkColumn);
|
|
if (!inClause) {
|
|
sb.append("=? ");
|
|
}
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Create the array of ExportedProperty used to build reference objects.
|
|
*/
|
|
private ExportedProperty[] createExported() {
|
|
|
|
BeanProperty idProp = descriptor.getIdProperty();
|
|
|
|
ArrayList<ExportedProperty> list = new ArrayList<>();
|
|
|
|
if (idProp != null && idProp.isEmbedded()) {
|
|
|
|
BeanPropertyAssocOne<?> one = (BeanPropertyAssocOne<?>) idProp;
|
|
BeanDescriptor<?> targetDesc = one.getTargetDescriptor();
|
|
BeanProperty[] emIds = targetDesc.propertiesBaseScalar();
|
|
try {
|
|
for (BeanProperty emId : emIds) {
|
|
ExportedProperty expProp = findMatch(true, emId);
|
|
list.add(expProp);
|
|
}
|
|
} catch (PersistenceException e) {
|
|
// not found as individual scalar properties
|
|
e.printStackTrace();
|
|
}
|
|
|
|
} else {
|
|
if (idProp != null) {
|
|
ExportedProperty expProp = findMatch(false, idProp);
|
|
list.add(expProp);
|
|
}
|
|
}
|
|
|
|
return list.toArray(new ExportedProperty[list.size()]);
|
|
}
|
|
|
|
/**
|
|
* Find the matching foreignDbColumn for a given local property.
|
|
*/
|
|
private ExportedProperty findMatch(boolean embeddedProp, BeanProperty prop) {
|
|
|
|
String matchColumn = prop.getDbColumn();
|
|
|
|
String searchTable = tableJoin.getTable();
|
|
TableJoinColumn[] columns = tableJoin.columns();
|
|
|
|
for (TableJoinColumn column : columns) {
|
|
String matchTo = column.getLocalDbColumn();
|
|
|
|
if (matchColumn.equalsIgnoreCase(matchTo)) {
|
|
String foreignCol = column.getForeignDbColumn();
|
|
return new ExportedProperty(embeddedProp, foreignCol, prop);
|
|
}
|
|
}
|
|
|
|
String msg = "Error with the Join on [" + getFullBeanName()
|
|
+ "]. Could not find the matching foreign key for [" + matchColumn + "] in table[" + searchTable + "]?"
|
|
+ " Perhaps using a @JoinColumn with the name/referencedColumnName attributes swapped?";
|
|
throw new PersistenceException(msg);
|
|
}
|
|
|
|
|
|
@Override
|
|
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
|
if (!isTransient) {
|
|
localHelp.appendSelect(ctx, subQuery);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
|
if (!isTransient) {
|
|
localHelp.appendFrom(ctx, joinType);
|
|
if (sqlFormulaJoin != null) {
|
|
ctx.appendFormulaJoin(sqlFormulaJoin, joinType);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
|
return localHelp.readSet(ctx, bean);
|
|
}
|
|
|
|
/**
|
|
* Read the data from the resultSet effectively ignoring it and returning null.
|
|
*/
|
|
@Override
|
|
public Object read(DbReadContext ctx) throws SQLException {
|
|
// just read the resultSet incrementing the column index
|
|
// pass in null for the bean so any data read is ignored
|
|
return localHelp.read(ctx);
|
|
}
|
|
|
|
@Override
|
|
public void setValue(EntityBean bean, Object value) {
|
|
super.setValue(bean, value);
|
|
if (embedded && value instanceof EntityBean) {
|
|
setEmbeddedOwner(bean, value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* For embedded bean set the owner and all properties to be loaded (recursively).
|
|
*/
|
|
void setAllLoadedEmbedded(EntityBean owner) {
|
|
Object emb = getValue(owner);
|
|
if (emb != null) {
|
|
EntityBean embeddedBean = (EntityBean) emb;
|
|
embeddedBean._ebean_getIntercept().setEmbeddedOwner(owner, propertyIndex);
|
|
targetDescriptor.setAllLoaded(embeddedBean);
|
|
}
|
|
}
|
|
|
|
private void setEmbeddedOwner(EntityBean bean, Object value) {
|
|
((EntityBean) value)._ebean_getIntercept().setEmbeddedOwner(bean, propertyIndex);
|
|
}
|
|
|
|
@Override
|
|
public void setValueIntercept(EntityBean bean, Object value) {
|
|
super.setValueIntercept(bean, value);
|
|
if (embedded && value instanceof EntityBean) {
|
|
setEmbeddedOwner(bean, value);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void loadIgnore(DbReadContext ctx) {
|
|
localHelp.loadIgnore(ctx);
|
|
}
|
|
|
|
@Override
|
|
public void load(SqlBeanLoad sqlBeanLoad) {
|
|
Object dbVal = sqlBeanLoad.load(this);
|
|
if (embedded && sqlBeanLoad.isLazyLoad()) {
|
|
if (dbVal instanceof EntityBean) {
|
|
((EntityBean) dbVal)._ebean_getIntercept().setLoaded();
|
|
}
|
|
}
|
|
}
|
|
|
|
private AssocOneHelp createHelp(boolean embedded, boolean oneToOneExported) {
|
|
if (embedded) {
|
|
return new AssocOneHelpEmbedded(this);
|
|
} else if (oneToOneExported) {
|
|
return new AssocOneHelpRefExported(this);
|
|
} else {
|
|
if (targetInheritInfo != null) {
|
|
return new AssocOneHelpRefInherit(this);
|
|
} else {
|
|
return new AssocOneHelpRefSimple(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* JSON write property (non-recursive to other beans).
|
|
*/
|
|
@Override
|
|
public void jsonWriteForInsert(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
|
|
|
if (!jsonSerialize) {
|
|
return;
|
|
}
|
|
jsonWriteBean(writeJson, getValue(bean));
|
|
}
|
|
|
|
/**
|
|
* JSON write property value (non-recursive to other beans).
|
|
*/
|
|
@Override
|
|
public void jsonWriteValue(SpiJsonWriter writeJson, Object value) throws IOException {
|
|
if (!jsonSerialize) {
|
|
return;
|
|
}
|
|
jsonWriteBean(writeJson, value);
|
|
}
|
|
|
|
private void jsonWriteBean(SpiJsonWriter writeJson, Object value) throws IOException {
|
|
|
|
if (value instanceof EntityBean) {
|
|
if (embedded) {
|
|
writeJson.writeFieldName(name);
|
|
BeanDescriptor<?> refDesc = descriptor.getBeanDescriptor(value.getClass());
|
|
refDesc.jsonWriteForInsert(writeJson, (EntityBean)value);
|
|
|
|
} else {
|
|
jsonWriteTargetId(writeJson, (EntityBean)value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Just write the Id property of the ToOne property.
|
|
*/
|
|
private void jsonWriteTargetId(SpiJsonWriter writeJson, EntityBean childBean) throws IOException {
|
|
BeanProperty idProperty = targetDescriptor.getIdProperty();
|
|
if (idProperty != null) {
|
|
writeJson.writeStartObject(name);
|
|
idProperty.jsonWriteForInsert(writeJson, childBean);
|
|
writeJson.writeEndObject();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
|
|
|
if (!jsonSerialize) {
|
|
return;
|
|
}
|
|
|
|
Object value = getValueIntercept(bean);
|
|
if (value == null) {
|
|
writeJson.writeNullField(name);
|
|
|
|
} else {
|
|
if (writeJson.isParentBean(value)) {
|
|
// bi-directional and already rendered parent
|
|
|
|
} else {
|
|
// Hmmm, not writing complex non-entity bean
|
|
if (value instanceof EntityBean) {
|
|
writeJson.beginAssocOne(name, bean);
|
|
BeanDescriptor<?> refDesc = descriptor.getBeanDescriptor(value.getClass());
|
|
refDesc.jsonWrite(writeJson, (EntityBean) value, name);
|
|
writeJson.endAssocOne();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void jsonRead(ReadJson readJson, EntityBean bean) throws IOException {
|
|
if (jsonDeserialize && targetDescriptor != null) {
|
|
T assocBean = targetDescriptor.jsonRead(readJson, name);
|
|
setValue(bean, assocBean);
|
|
}
|
|
}
|
|
|
|
public boolean isReference(Object detailBean) {
|
|
EntityBean eb = (EntityBean) detailBean;
|
|
return targetDescriptor.isReference(eb._ebean_getIntercept());
|
|
}
|
|
|
|
/**
|
|
* Set the parent bean to the child bean if it has not already been set.
|
|
*/
|
|
public void setParentBeanToChild(EntityBean parent, EntityBean child) {
|
|
|
|
if (mappedBy != null) {
|
|
BeanProperty beanProperty = targetDescriptor.getBeanProperty(mappedBy);
|
|
if (beanProperty != null && beanProperty.getValue(child) == null) {
|
|
// set the 'parent' bean to the 'child' bean
|
|
beanProperty.setValue(child, parent);
|
|
}
|
|
}
|
|
}
|
|
}
|