mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-24 23:56:36 +00:00
#595 - Refactor - persistence context root type handling - contextGet() and contextRef()
This commit is contained in:
@@ -580,47 +580,31 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
BeanDescriptor desc = getBeanDescriptor(type);
|
||||
// convert the id type if necessary
|
||||
id = desc.convertId(id);
|
||||
|
||||
Object ref = null;
|
||||
PersistenceContext ctx = null;
|
||||
|
||||
PersistenceContext pc = null;
|
||||
SpiTransaction t = transactionScopeManager.get();
|
||||
if (t != null) {
|
||||
// first try the persistence context
|
||||
ctx = t.getPersistenceContext();
|
||||
ref = ctx.get(type, id);
|
||||
}
|
||||
|
||||
if (ref == null) {
|
||||
InheritInfo inheritInfo = desc.getInheritInfo();
|
||||
if (inheritInfo != null) {
|
||||
// we actually need to do a query because
|
||||
// we don't know the type without the
|
||||
// discriminator value
|
||||
BeanProperty idProp = desc.getIdProperty();
|
||||
if (idProp == null) {
|
||||
throw new PersistenceException("No ID properties for this type? " + desc);
|
||||
}
|
||||
|
||||
// just select the id properties and
|
||||
// the discriminator column (auto added)
|
||||
Query<T> query = createQuery(type);
|
||||
query.select(idProp.getName()).setId(id);
|
||||
|
||||
ref = query.findUnique();
|
||||
|
||||
} else {
|
||||
// use the default reference options
|
||||
ref = desc.createReference(null, id);
|
||||
}
|
||||
|
||||
if (ctx != null) {
|
||||
desc.contextPut(ctx, id, ref);
|
||||
pc = t.getPersistenceContext();
|
||||
Object existing = desc.contextGet(pc, id);
|
||||
if (existing != null) {
|
||||
return (T)existing;
|
||||
}
|
||||
}
|
||||
return (T) ref;
|
||||
|
||||
InheritInfo inheritInfo = desc.getInheritInfo();
|
||||
if (inheritInfo == null) {
|
||||
return (T)desc.contextRef(pc, null, id);
|
||||
}
|
||||
|
||||
BeanProperty idProp = desc.getIdProperty();
|
||||
if (idProp == null) {
|
||||
throw new PersistenceException("No ID properties for this type? " + desc);
|
||||
}
|
||||
|
||||
// we actually need to do a query because we don't know the type without the discriminator
|
||||
// value, just select the id property and discriminator column (auto added)
|
||||
return find(type).select(idProp.getName()).setId(id).findUnique();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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.query.SqlJoinType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
@@ -13,8 +15,11 @@ abstract class AssocOneHelp {
|
||||
|
||||
protected final BeanPropertyAssocOne property;
|
||||
|
||||
protected final BeanDescriptor target;
|
||||
|
||||
AssocOneHelp(BeanPropertyAssocOne property) {
|
||||
this.property = property;
|
||||
this.target = property.targetDescriptor;
|
||||
}
|
||||
/**
|
||||
* Effectively skip reading (the jdbc resultSet as already in the persistence context etc).
|
||||
@@ -26,7 +31,26 @@ abstract class AssocOneHelp {
|
||||
/**
|
||||
* Read and return the bean.
|
||||
*/
|
||||
abstract Object read(DbReadContext ctx) throws SQLException;
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
// Support for Inheritance hierarchy on exported OneToOne ?
|
||||
Object id = property.targetIdBinder.read(ctx);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
Object existing = target.contextGet(pc, id);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
Object ref = target.contextRef(pc, ctx.isReadOnly(), id);
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
ctx.register(property.name, ebi);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read setting values into the bean.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Helper for BeanPropertyAssocOne for OneToOne exported reference - not so common.
|
||||
*/
|
||||
class AssocOneHelpRefExported extends AssocOneHelp {
|
||||
|
||||
public AssocOneHelpRefExported(BeanPropertyAssocOne property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append columns for foreign key columns.
|
||||
*/
|
||||
@Override
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
|
||||
// set appropriate tableAlias for the exported id columns
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
ctx.pushTableAlias(relativePrefix);
|
||||
property.targetIdBinder.appendSelect(ctx, subQuery);
|
||||
ctx.popTableAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ 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.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
@@ -36,30 +36,24 @@ class AssocOneHelpRefInherit extends AssocOneHelp {
|
||||
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);
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
BeanDescriptor<?> desc = rowInheritInfo.getBeanDescriptor();
|
||||
Object existing = desc.contextGet(pc, 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);
|
||||
|
||||
Object ref = desc.contextRef(pc, ctx.isReadOnly(), id);
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
ctx.register(property.name, ebi);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +1,12 @@
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
-61
@@ -1,61 +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.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Helper for BeanPropertyAssocOne for OneToOne exported reference - not so common.
|
||||
*/
|
||||
final class AssocOneHelpReferenceExported extends AssocOneHelp {
|
||||
|
||||
public AssocOneHelpReferenceExported(BeanPropertyAssocOne property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
// Support for Inheritance hierarchy on exported OneToOne ?
|
||||
Object id = property.targetIdBinder.read(ctx);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
Object existing = pc.get(property.targetType, id);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
Object ref = property.targetDescriptor.createReference(ctx.isReadOnly(), id);
|
||||
property.targetDescriptor.contextPut(pc, 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) {
|
||||
|
||||
// set appropriate tableAlias for the exported id columns
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
ctx.pushTableAlias(relativePrefix);
|
||||
property.targetIdBinder.appendSelect(ctx, subQuery);
|
||||
ctx.popTableAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
@@ -1668,6 +1668,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context.
|
||||
*/
|
||||
public Object contextGet(PersistenceContext pc, Object id) {
|
||||
return pc.get(rootBeanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the bean into the persistence context.
|
||||
*/
|
||||
@@ -1682,6 +1689,17 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return pc.putIfAbsent(rootBeanType, id, localBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reference bean and put it in the persistence context (and return it).
|
||||
*/
|
||||
public Object contextRef(PersistenceContext pc, Boolean readOnly, Object id) {
|
||||
Object ref = createReference(readOnly, id);
|
||||
if (pc != null) {
|
||||
contextPut(pc, id, ref);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to return the unique property. If only one property makes up
|
||||
* the unique id then it's value is returned. If there is a concatenated
|
||||
|
||||
@@ -632,7 +632,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
if (embedded) {
|
||||
return new AssocOneHelpEmbedded(this);
|
||||
} else if (oneToOneExported) {
|
||||
return new AssocOneHelpReferenceExported(this);
|
||||
return new AssocOneHelpRefExported(this);
|
||||
} else {
|
||||
if (targetInheritInfo != null) {
|
||||
return new AssocOneHelpRefInherit(this);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.tests.model.basic.Car;
|
||||
import com.avaje.tests.model.basic.Customer;
|
||||
import com.avaje.tests.model.basic.ResetBasicData;
|
||||
import com.avaje.tests.model.basic.Vehicle;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class DefaultServer_getReferenceTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void getReference_noPC() {
|
||||
Ebean.getReference(Customer.class, 42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getReference_when_inPC_expect_getFromPC() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
Customer loaded = Ebean.find(Customer.class, 1);
|
||||
Customer reference = Ebean.getReference(Customer.class, 1);
|
||||
assertThat(loaded).isSameAs(reference);
|
||||
|
||||
} finally {
|
||||
Ebean.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void inherit_getReference_when_noPC() {
|
||||
|
||||
Car car = new Car();
|
||||
car.setDriver("TestForRef");
|
||||
Ebean.save(car);
|
||||
|
||||
Vehicle reference = Ebean.getReference(Vehicle.class, car.getId());
|
||||
|
||||
assertThat(reference).isInstanceOf(Car.class);
|
||||
assertThat(reference.getId()).isSameAs(car.getId());
|
||||
|
||||
Ebean.delete(car);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void inherit_getReference_when_inPC() {
|
||||
|
||||
Car car = new Car();
|
||||
car.setDriver("TestForRef");
|
||||
Ebean.save(car);
|
||||
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
Vehicle loaded = Ebean.find(Vehicle.class, car.getId());
|
||||
Vehicle reference = Ebean.getReference(Vehicle.class, car.getId());
|
||||
assertThat(reference).isSameAs(loaded);
|
||||
|
||||
} finally {
|
||||
Ebean.endTransaction();
|
||||
}
|
||||
|
||||
Ebean.delete(car);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user