#595 - Refactor - persistence context root type handling - AssocOne split simple and inherit

This commit is contained in:
Robin Bygrave
2016-03-11 19:40:02 +13:00
parent cf62ea4c2f
commit cf783fbbb7
11 changed files with 338 additions and 306 deletions
@@ -11,10 +11,17 @@ import java.sql.SQLException;
*/
abstract class AssocOneHelp {
protected final BeanPropertyAssocOne property;
AssocOneHelp(BeanPropertyAssocOne property) {
this.property = property;
}
/**
* Effectively skip reading (the jdbc resultSet as already in the persistence context etc).
*/
abstract void loadIgnore(DbReadContext ctx);
void loadIgnore(DbReadContext ctx) {
property.targetIdBinder.loadIgnore(ctx);
}
/**
* Read and return the bean.
@@ -24,7 +31,14 @@ abstract class AssocOneHelp {
/**
* Read setting values into the bean.
*/
abstract Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException;
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object val = read(ctx);
if (bean != null) {
property.setValue(bean, val);
ctx.propagateState(val);
}
return val;
}
/**
* Append to the select clause.
@@ -34,6 +48,8 @@ abstract class AssocOneHelp {
/**
* Append to the from clause.
*/
abstract void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
// nothing required here
}
}
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import java.sql.SQLException;
@@ -10,15 +9,13 @@ import java.sql.SQLException;
*/
final class AssocOneHelpEmbedded extends AssocOneHelp {
private BeanPropertyAssocOne beanPropertyAssocOne;
public AssocOneHelpEmbedded(BeanPropertyAssocOne beanPropertyAssocOne) {
this.beanPropertyAssocOne = beanPropertyAssocOne;
public AssocOneHelpEmbedded(BeanPropertyAssocOne property) {
super(property);
}
void loadIgnore(DbReadContext ctx) {
for (int i = 0; i < beanPropertyAssocOne.embeddedProps.length; i++) {
beanPropertyAssocOne.embeddedProps[i].loadIgnore(ctx);
for (int i = 0; i < property.embeddedProps.length; i++) {
property.embeddedProps[i].loadIgnore(ctx);
}
}
@@ -27,10 +24,9 @@ final class AssocOneHelpEmbedded extends AssocOneHelp {
Object dbVal = read(ctx);
if (bean != null) {
// set back to the parent bean
beanPropertyAssocOne.setValue(bean, dbVal);
property.setValue(bean, dbVal);
ctx.propagateState(dbVal);
return dbVal;
} else {
return null;
}
@@ -39,11 +35,11 @@ final class AssocOneHelpEmbedded extends AssocOneHelp {
@Override
Object read(DbReadContext ctx) throws SQLException {
EntityBean embeddedBean = beanPropertyAssocOne.targetDescriptor.createEntityBean();
EntityBean embeddedBean = property.targetDescriptor.createEntityBean();
boolean notNull = false;
for (int i = 0; i < beanPropertyAssocOne.embeddedProps.length; i++) {
Object value = beanPropertyAssocOne.embeddedProps[i].readSet(ctx, embeddedBean);
for (int i = 0; i < property.embeddedProps.length; i++) {
Object value = property.embeddedProps[i].readSet(ctx, embeddedBean);
if (value != null) {
notNull = true;
}
@@ -56,14 +52,10 @@ final class AssocOneHelpEmbedded extends AssocOneHelp {
}
}
@Override
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
}
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
for (int i = 0; i < beanPropertyAssocOne.embeddedProps.length; i++) {
beanPropertyAssocOne.embeddedProps[i].appendSelect(ctx, subQuery);
for (int i = 0; i < property.embeddedProps.length; i++) {
property.embeddedProps[i].appendSelect(ctx, subQuery);
}
}
}
@@ -0,0 +1,88 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContextUtil;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import java.sql.SQLException;
/**
* Helper for BeanPropertyAssocOne imported reference but with inheritance.
*/
class AssocOneHelpRefInherit extends AssocOneHelp {
private final InheritInfo inherit;
AssocOneHelpRefInherit(BeanPropertyAssocOne property) {
super(property);
this.inherit = property.targetInheritInfo;
}
@Override
void loadIgnore(DbReadContext ctx) {
property.targetIdBinder.loadIgnore(ctx);
ctx.getDataReader().incrementPos(1);
}
/**
* Read and set a Reference bean.
*/
@Override
Object read(DbReadContext ctx) throws SQLException {
// read discriminator to determine the type
InheritInfo rowInheritInfo = inherit.readType(ctx);
if (rowInheritInfo == null) {
return null;
}
BeanDescriptor<?> desc = rowInheritInfo.getBeanDescriptor();
// read the foreign key column(s)
Object id = property.targetIdBinder.read(ctx);
if (id == null) {
return null;
}
// check transaction context to see if it already exists
Class<?> rowType = desc.rootBeanType;
Object existing = ctx.getPersistenceContext().get(rowType, id);
if (existing != null) {
return existing;
}
// for inheritance hierarchy create the correct type for this row...
Object ref = desc.createReference(ctx.isReadOnly(), id);
Class<?> rootType = PersistenceContextUtil.root(ref.getClass());
ctx.getPersistenceContext().put(rootType, id, ref);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
ctx.register(property.name, ebi);
return ref;
}
@Override
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
// add join to support the discriminator column
String relativePrefix = ctx.getRelativePrefix(property.name);
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
}
/**
* Append columns for foreign key columns.
*/
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!subQuery) {
// add discriminator column
String relativePrefix = ctx.getRelativePrefix(property.getName());
String tableAlias = ctx.getTableAlias(relativePrefix);
ctx.appendColumn(tableAlias, property.targetInheritInfo.getDiscriminatorColumn());
}
property.importedId.sqlAppend(ctx);
}
}
@@ -0,0 +1,56 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import java.sql.SQLException;
/**
* Helper for BeanPropertyAssocOne imported reference - this is the common case.
*/
class AssocOneHelpRefSimple extends AssocOneHelp {
private final BeanDescriptor target;
AssocOneHelpRefSimple(BeanPropertyAssocOne property) {
super(property);
this.target = property.targetDescriptor;
}
/**
* Read and set a Reference bean.
*/
@Override
Object read(DbReadContext ctx) throws SQLException {
// read the foreign key column(s)
Object id = property.targetIdBinder.read(ctx);
if (id == null) {
return null;
}
Class<?> rowType = property.targetType;
// check transaction context to see if it already exists
Object existing = ctx.getPersistenceContext().get(rowType, id);
if (existing != null) {
return existing;
}
Object ref = target.createReference(ctx.isReadOnly(), id);
target.contextPut(ctx.getPersistenceContext(), id, ref);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
ctx.register(property.name, ebi);
return ref;
}
/**
* Append columns for foreign key columns.
*/
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
property.importedId.sqlAppend(ctx);
}
}
@@ -1,120 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContextUtil;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import java.sql.SQLException;
/**
* Helper for BeanPropertyAssocOne imported reference - this is the common case.
*/
final class AssocOneHelpReference extends AssocOneHelp {
private BeanPropertyAssocOne beanPropertyAssocOne;
AssocOneHelpReference(BeanPropertyAssocOne beanPropertyAssocOne) {
this.beanPropertyAssocOne = beanPropertyAssocOne;
}
@Override
void loadIgnore(DbReadContext ctx) {
beanPropertyAssocOne.targetIdBinder.loadIgnore(ctx);
if (beanPropertyAssocOne.targetInheritInfo != null) {
ctx.getDataReader().incrementPos(1);
}
}
@Override
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object val = read(ctx);
if (bean != null) {
beanPropertyAssocOne.setValue(bean, val);
ctx.propagateState(val);
}
return val;
}
/**
* Read and set a Reference bean.
*/
@Override
Object read(DbReadContext ctx) throws SQLException {
BeanDescriptor<?> rowDescriptor = null;
Class<?> rowType = beanPropertyAssocOne.targetType;
if (beanPropertyAssocOne.targetInheritInfo != null) {
// read discriminator to determine the type
InheritInfo rowInheritInfo = beanPropertyAssocOne.targetInheritInfo.readType(ctx);
if (rowInheritInfo != null) {
rowType = rowInheritInfo.getType();
rowDescriptor = rowInheritInfo.getBeanDescriptor();
}
}
// read the foreign key column(s)
Object id = beanPropertyAssocOne.targetIdBinder.read(ctx);
if (id == null) {
return null;
}
// check transaction context to see if it already exists
Object existing = ctx.getPersistenceContext().get(rowType, id);
if (existing != null) {
return existing;
}
Boolean readOnly = ctx.isReadOnly();
Object ref;
if (beanPropertyAssocOne.targetInheritInfo != null) {
// for inheritance hierarchy create the correct type for this row...
ref = rowDescriptor.createReference(readOnly, id);
} else {
ref = beanPropertyAssocOne.targetDescriptor.createReference(readOnly, id);
}
Class<?> rootType = PersistenceContextUtil.root(ref.getClass());
Object existingBean = ctx.getPersistenceContext().putIfAbsent(rootType, id, ref);
if (existingBean != null) {
// advanced case when we use multiple concurrent threads to
// build a single object graph, and another thread has since
// loaded a matching bean so we will use that instead.
ref = existingBean;
} else {
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
if (Boolean.TRUE.equals(ctx.isReadOnly())) {
ebi.setReadOnly(true);
}
ctx.register(beanPropertyAssocOne.name, ebi);
}
return ref;
}
@Override
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
if (beanPropertyAssocOne.targetInheritInfo != null) {
// add join to support the discriminator column
String relativePrefix = ctx.getRelativePrefix(beanPropertyAssocOne.name);
beanPropertyAssocOne.tableJoin.addJoin(joinType, relativePrefix, ctx);
}
}
/**
* Append columns for foreign key columns.
*/
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!subQuery && beanPropertyAssocOne.targetInheritInfo != null) {
// add discriminator column
String relativePrefix = ctx.getRelativePrefix(beanPropertyAssocOne.getName());
String tableAlias = ctx.getTableAlias(relativePrefix);
ctx.appendColumn(tableAlias, beanPropertyAssocOne.targetInheritInfo.getDiscriminatorColumn());
}
beanPropertyAssocOne.importedId.sqlAppend(ctx);
}
}
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import java.sql.SQLException;
@@ -13,55 +12,30 @@ import java.sql.SQLException;
*/
final class AssocOneHelpReferenceExported extends AssocOneHelp {
private BeanPropertyAssocOne beanPropertyAssocOne;
public AssocOneHelpReferenceExported(BeanPropertyAssocOne beanPropertyAssocOne) {
this.beanPropertyAssocOne = beanPropertyAssocOne;
}
@Override
void loadIgnore(DbReadContext ctx) {
beanPropertyAssocOne.targetDescriptor.getIdBinder().loadIgnore(ctx);
}
/**
* Read and set a Reference bean.
*/
@Override
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object dbVal = read(ctx);
if (bean != null) {
beanPropertyAssocOne.setValue(bean, dbVal);
ctx.propagateState(dbVal);
}
return dbVal;
public AssocOneHelpReferenceExported(BeanPropertyAssocOne property) {
super(property);
}
@Override
Object read(DbReadContext ctx) throws SQLException {
// TODO: Support for Inheritance hierarchy on exported OneToOne ?
IdBinder idBinder = beanPropertyAssocOne.targetDescriptor.getIdBinder();
Object id = idBinder.read(ctx);
// Support for Inheritance hierarchy on exported OneToOne ?
Object id = property.targetIdBinder.read(ctx);
if (id == null) {
return null;
}
PersistenceContext persistCtx = ctx.getPersistenceContext();
Object existing = persistCtx.get(beanPropertyAssocOne.targetType, id);
PersistenceContext pc = ctx.getPersistenceContext();
Object existing = pc.get(property.targetType, id);
if (existing != null) {
return existing;
}
Object ref = beanPropertyAssocOne.targetDescriptor.createReference(ctx.isReadOnly(), id);
Object ref = property.targetDescriptor.createReference(ctx.isReadOnly(), id);
property.targetDescriptor.contextPut(pc, id, ref);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
if (Boolean.TRUE.equals(ctx.isReadOnly())) {
ebi.setReadOnly(true);
}
beanPropertyAssocOne.targetDescriptor.contextPut(persistCtx, id, ref);
ctx.register(beanPropertyAssocOne.name, ebi);
ctx.register(property.name, ebi);
return ref;
}
@@ -72,20 +46,16 @@ final class AssocOneHelpReferenceExported extends AssocOneHelp {
void appendSelect(DbSqlContext ctx, boolean subQuery) {
// set appropriate tableAlias for the exported id columns
String relativePrefix = ctx.getRelativePrefix(beanPropertyAssocOne.getName());
String relativePrefix = ctx.getRelativePrefix(property.getName());
ctx.pushTableAlias(relativePrefix);
IdBinder idBinder = beanPropertyAssocOne.targetDescriptor.getIdBinder();
idBinder.appendSelect(ctx, subQuery);
property.targetIdBinder.appendSelect(ctx, subQuery);
ctx.popTableAlias();
}
@Override
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
String relativePrefix = ctx.getRelativePrefix(beanPropertyAssocOne.getName());
beanPropertyAssocOne.tableJoin.addJoin(joinType, relativePrefix, ctx);
String relativePrefix = ctx.getRelativePrefix(property.getName());
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
}
}
@@ -194,7 +194,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* The type of bean this describes.
*/
private final Class<T> beanType;
private final Class<?> rootBeanType;
protected final Class<?> rootBeanType;
/**
* This is not sent to a remote client.
@@ -1528,14 +1528,14 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
}
try {
EntityBean eb = createEntityBean();
convertSetId(id, eb);
EntityBeanIntercept ebi = eb._ebean_getIntercept();
ebi.setBeanLoader(ebeanServer);
// Note: not creating proxies for many's...
ebi.setReference(idPropertyIndex);
if (Boolean.TRUE == readOnly) {
ebi.setReadOnly(true);
}
return (T) eb;
@@ -37,7 +37,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
protected final boolean importedPrimaryKey;
protected final AssocOneHelp localHelp;
protected AssocOneHelp localHelp;
protected final BeanProperty[] embeddedProps;
@@ -87,12 +87,13 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
embeddedProps = null;
embeddedPropsMap = null;
}
localHelp = createHelp(embedded, oneToOneExported);
}
@Override
public void initialise() {
super.initialise();
localHelp = createHelp(embedded, oneToOneExported);
if (!isTransient) {
//noinspection StatementWithEmptyBody
if (embedded) {
@@ -633,7 +634,11 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
} else if (oneToOneExported) {
return new AssocOneHelpReferenceExported(this);
} else {
return new AssocOneHelpReference(this);
if (targetInheritInfo != null) {
return new AssocOneHelpRefInherit(this);
} else {
return new AssocOneHelpRefSimple(this);
}
}
}