Compare commits

...
Author SHA1 Message Date
Rob Bygrave fcb9df05ad [maven-release-plugin] prepare release avaje-ebeanorm-3.3.3 2014-05-19 01:03:31 +12:00
Rob Bygrave 3de79b211a Change version in pom to 3.3.3-SNAPSHOT in preparation for release 2014-05-19 01:02:13 +12:00
Rob Bygrave d93952a920 Backport of fix for #56 - Using findIterate with MySQL streams 2014-05-19 00:59:05 +12:00
Rob Bygrave 3b4836cad9 [maven-release-plugin] prepare release avaje-ebeanorm-3.3.2 2014-04-03 23:18:50 +13:00
Rob Bygrave 6048d97aab Update version in README 2014-04-03 23:17:24 +13:00
Rob Bygrave 16d32b408e Merge branch 'master' of https://github.com/ebean-orm/avaje-ebeanorm 2014-04-03 23:15:01 +13:00
Rob Bygrave 0435ab0991 Fix for #84 Fix for classpath searching with maven surefire / jarfile with manifest 2014-04-03 23:14:55 +13:00
rob 95617d1bea Update README with pom version 2014-04-03 09:12:28 +13:00
Rob Bygrave 38d0e7642e [maven-release-plugin] prepare for next development iteration 2014-04-02 21:59:57 +13:00
Rob Bygrave e4306ce1ab [maven-release-plugin] prepare release avaje-ebeanorm-3.3.1 2014-04-02 21:59:46 +13:00
Rob Bygrave 444b656780 Update pom to 3.3.1 2014-04-02 21:58:13 +13:00
Rob Bygrave fcbba23441 Test case for #83 - Bug: Stateless update cascading to OneToOne or
ManyToOne incorrectly tries to INSERT rather than UPDATE
2014-04-02 21:44:41 +13:00
Rob Bygrave 18961047a1 Fix for #80 - Exposing discriminator value in entity bean throws
exception when updating or deleting
2014-03-31 22:49:44 +13:00
Rob Bygrave 34347fc3e1 Fix for #77 - NPE when lazy loading on a OneToMany that is not a leaf 2014-03-31 22:06:10 +13:00
Rob Bygrave 189e0a2ea9 Part of fix for #79 - moving deactivate() and notifyCommit() into finally block 2014-03-21 21:54:47 +13:00
Rob Bygrave 182e027521 Further changes for #79 - returning/cleanup of bad connection 2014-03-21 02:42:41 +13:00
Rob Bygrave f85fa2c21d Fix for #79 - Rollback in case of connection closed - deactivate() not called when connection.rollback() fails 2014-03-20 20:14:14 +13:00
Rob Bygrave 5a5f479568 Merge pull request #81 from rvowles/master
assume that if includes are specified then turn default includes off
2014-03-16 15:02:28 +13:00
Rob Bygrave 9ca2486c9c Change defaultJarMatch back to default to false (as per previous release) 2014-03-16 14:31:21 +13:00
Richard Vowles 656b239925 assume that if includes are specified then turn default includes off 2014-03-16 13:11:51 +13:00
Rob Bygrave 5d46904341 Fix for introduced issue with sub-query expression 2014-03-16 00:05:43 +13:00
Rob Bygrave f0dd069ed2 Fix for #70 - @PrivateOwned makes Ebean try to remove non persistent objects from DB and throws OptimisticLockException 2014-03-15 13:48:56 +13:00
Rob Bygrave 5bd454bdc0 Merge pull request #76 from icaromuniz/master
Adding test case TestPrivateOwnedIgnoreTransientOrphan related to issue #70
2014-03-15 13:14:17 +13:00
Rob Bygrave eeebaf9a08 Fix for #78 - Wrong collection used in excludeJar 2014-03-15 12:53:58 +13:00
Rob Bygrave 636a148509 Fix for #79 - Rollback in case of connection closed 2014-03-15 12:45:44 +13:00
Icaro Muniz 170cd6051e Adding test case TestPrivateOwnedIgnoreTransientOrphan 2014-02-26 09:23:35 -03:00
Rob Bygrave 522fc2384c [maven-release-plugin] prepare for next development iteration 2014-01-31 02:12:20 +13:00
27 changed files with 603 additions and 65 deletions
+4 -4
View File
@@ -1,14 +1,14 @@
avaje-ebeanorm-server
=====================
avaje-ebeanorm
==============
The internal server implementation of EbeanORM API
Main EbeanORM artifact
Maven Dependency
----------------
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>3.2.5</version>
<version>3.3.2</version>
</dependency>
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>3.3.1-RC2</version>
<version>3.3.3</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -170,7 +170,7 @@
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>3.2.2</version>
<version>3.3.2</version>
<executions>
<execution>
<id>main</id>
@@ -2,6 +2,11 @@ package com.avaje.ebeaninternal.server.core;
import java.sql.Connection;
import javax.persistence.PersistenceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiTransaction;
@@ -11,6 +16,8 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
*/
public abstract class BeanRequest {
private static final Logger log = LoggerFactory.getLogger(BeanRequest.class);
/**
* The server processing the request.
*/
@@ -84,7 +91,14 @@ public abstract class BeanRequest {
*/
public void rollbackTransIfRequired() {
if (createdTransaction) {
transaction.rollback();
try {
transaction.rollback();
} catch (PersistenceException e) {
// Just log this and carry on. A previous exception has been
// thrown and if this rollback throws exception it likely means
// that the connection is broken (and the datasource and db will cleanup)
log.error("Error trying to rollack a transaction (after a prior exception thrown)", e);
}
}
}
@@ -82,16 +82,22 @@ public class BootupClassPathSearch {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.addDefaultExcludePackages();
if (packages != null) {
if (packages != null && packages.size() > 0) {
for (String packageName : packages) {
filter.includePackage(packageName);
}
// if they specified include packages, they don't want by default to include everything
filter.setDefaultPackageMatch(false);
}
if (jars != null) {
if (jars != null && jars.size() > 0) {
for (String jarName : jars) {
filter.includeJar(jarName);
}
// if they specified jars to specifically include, they don't want everything included
filter.setDefaultJarMatch(false);
}
return filter;
@@ -43,7 +43,8 @@ final class NotExpression implements SpiExpression {
}
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
queryAutoFetchHash(builder);
builder.add(NotExpression.class);
exp.queryPlanHash(request, builder);
}
public int queryBindHash() {
@@ -597,12 +597,35 @@ public class DataSourcePool implements DataSource {
*/
protected void returnConnection(PooledConnection pooledConnection) {
if (poolListener != null) {
poolListener.onBeforeReturnConnection(pooledConnection);
}
queue.returnPooledConnection(pooledConnection);
// return a normal 'good' connection
returnTheConnection(pooledConnection, false);
}
/**
* This is a bad connection and must be removed from the pool's busy list and fully closed.
*/
protected void returnConnectionForceClose(PooledConnection pooledConnection) {
returnTheConnection(pooledConnection, true);
}
/**
* Return connection. If forceClose is true then this is a bad connection that
* must be removed and closed fully.
*/
private void returnTheConnection(PooledConnection pooledConnection, boolean forceClose) {
if (poolListener != null && !forceClose) {
poolListener.onBeforeReturnConnection(pooledConnection);
}
queue.returnPooledConnection(pooledConnection, forceClose);
if (forceClose) {
// Got a bad connection so check the pool
checkDataSource();
}
}
/**
* Collect statistics of a connection that is fully closing
*/
@@ -508,9 +508,8 @@ public class PooledConnection extends ConnectionDelegator {
if (hadErrors) {
if (!pool.validateConnection(this)) {
// the connection is BAD, close it and test the pool
closeConnectionFully(false);
pool.checkDataSource();
// the connection is BAD, remove it, close it and test the pool
pool.returnConnectionForceClose(this);
return;
}
}
@@ -535,10 +534,9 @@ public class PooledConnection extends ConnectionDelegator {
pool.returnConnection(this);
} catch (Exception ex) {
// the connection is BAD, close it and test the pool
// the connection is BAD, remove it, close it and test the pool
logger.warn("Error when trying to return connection to pool, closing fully.", ex);
closeConnectionFully(false);
pool.checkDataSource();
pool.returnConnectionForceClose(this);
}
}
@@ -238,7 +238,7 @@ public class PooledConnectionQueue {
/**
* Return a PooledConnection.
*/
protected void returnPooledConnection(PooledConnection c) {
protected void returnPooledConnection(PooledConnection c, boolean forceClose) {
final ReentrantLock lock = this.lock;
lock.lock();
@@ -246,7 +246,7 @@ public class PooledConnectionQueue {
if (!busyList.remove(c)) {
logger.error("Connection [{}] not found in BusyList? ", c);
}
if (c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) {
if (forceClose || c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) {
c.closeConnectionFully(false);
} else {
@@ -764,7 +764,14 @@ public final class DefaultPersister implements Persister {
// increase depth for batching order
t.depth(+1);
for (Object removedBean : modifyRemovals) {
deleteRecurse(removedBean, t);
if (removedBean instanceof EntityBean) {
EntityBean eb = (EntityBean)removedBean;
if (eb._ebean_getIntercept().isLoaded()) {
// only delete if the bean was loaded meaning that
// it is know to exist in the DB
deleteRecurse(removedBean, t);
}
}
}
t.depth(-1);
}
@@ -47,12 +47,16 @@ public class FactoryBaseProperties {
for (int i = 0; i < props.length; i++) {
if(DmlMode.WHERE.equals(mode) && !withLobs && !props[i].isDbUpdatable()) {
// skip non-updatable column from where clause
} else {
Bindable item = factoryProperty.create(props[i], mode, withLobs);
if (item != null) {
list.add(item);
} else {
// null where readOnly (Secondary tables) or Lob exclusion
}
}
}
}
@@ -386,6 +386,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
if (forwardOnlyHint) {
// Use forward only hints for large resultset processing (Issue 56, MySql specific)
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pstmt.setFetchSize(Integer.MIN_VALUE);
} else {
pstmt = conn.prepareStatement(sql);
}
@@ -5,6 +5,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.Monitor;
@@ -124,7 +126,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
private ClassContext getClassContext(Class<?> beanType) {
String clsName = beanType.getName();
String clsName = getBeanBaseType(beanType).getName();
ClassContext classMap = typeCache.get(clsName);
if (classMap == null) {
classMap = new ClassContext();
@@ -132,6 +134,16 @@ public final class DefaultPersistenceContext implements PersistenceContext {
}
return classMap;
}
private Class<?> getBeanBaseType(Class<?> beanType) {
Class<?> parent = beanType.getSuperclass();
while (parent != null && parent.isAnnotationPresent(Entity.class)) {
beanType = parent;
parent = parent.getSuperclass();
}
return beanType;
}
private static class ClassContext {
@@ -593,12 +593,14 @@ public class JdbcTransaction implements SpiTransaction {
}
connection.commit();
}
// these will not throw an exception
deactivate();
notifyCommit();
} catch (Exception e) {
throw new RollbackException(e);
} finally {
// these will not throw an exception
deactivate();
notifyCommit();
}
}
@@ -634,12 +636,13 @@ public class JdbcTransaction implements SpiTransaction {
try {
connection.rollback();
} catch (Exception ex) {
throw new PersistenceException(ex);
} finally {
// these will not throw an exception
deactivate();
notifyRollback(cause);
} catch (Exception ex) {
throw new PersistenceException(ex);
}
}
@@ -10,7 +10,6 @@ import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -26,10 +25,6 @@ import org.slf4j.LoggerFactory;
import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.server.util.ClassPathReader;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
import com.avaje.ebeaninternal.server.util.DefaultClassPathReader;
/**
* Can search the class path for classes using a ClassPathSearchMatcher. A
@@ -45,8 +40,8 @@ public class ClassPathSearch {
private ClassLoader classLoader;
private Object[] classPaths;
private List<Object> classPath = new ArrayList<Object>();
private ClassPathSearchFilter filter;
private ClassPathSearchMatcher matcher;
@@ -79,16 +74,27 @@ public class ClassPathSearch {
classPathReader = (ClassPathReader) ClassUtil.newInstance(cn, this.getClass());
}
classPaths = classPathReader.readPath(classLoader);
Object[] rawClassPaths = classPathReader.readPath(classLoader);
if (classPaths == null || classPaths.length == 0) {
String msg = "ClassPath is EMPTY using ClassPathReader [" + classPathReader + "]";
logger.warn(msg);
if (rawClassPaths == null || rawClassPaths.length == 0) {
logger.warn("ClassPath is EMPTY using ClassPathReader [" + classPathReader + "]");
return;
}
for (int i = 0; i < rawClassPaths.length; i++) {
// check for a jarfile with a manifest classpath (e.g. maven surefire)
List<URI> classPathFromManifest = getClassPathFromManifest(rawClassPaths[i]);
if (classPathFromManifest.isEmpty()) {
classPath.add(rawClassPaths[i]);
} else {
classPath.addAll(classPathFromManifest);
}
}
boolean debug = GlobalProperties.getBoolean("ebean.debug.classpath", false);
if (debug || logger.isTraceEnabled()) {
logger.info("Classpath " + Arrays.toString(classPaths));
if (logger.isDebugEnabled()) {
for (Object entry : classPath) {
logger.debug("Classpath Entry: {}",entry);
}
}
} catch (Exception e) {
@@ -133,47 +139,52 @@ public class ClassPathSearch {
*/
public List<Class<?>> findClasses() throws IOException {
if (classPaths == null || classPaths.length == 0) {
if (classPath.isEmpty()) {
// returning an empty list
return matchList;
}
for (int i = 0; i < classPaths.length; i++) {
int classPathSize = classPath.size();
for (int i = 0; i < classPathSize; i++) {
ClassPathElement element = getClassPathElement(classPaths[i]);
ClassPathElement element = getClassPathElement(classPath.get(i));
if (element.isDirectory()) {
scanDirectory(element);
} else if (element.isJarOrWar()) {
// search name including the ! offset if it is there
if (filter.isSearchJar(element.getJarNameWithOffset())) {
if (classPathSize == 1 || filter.isSearchJar(element.getJarNameWithOffset())) {
scanJar(element);
}
} else {
String msg = "Error: expected classPath entry [" + element
+ "] to be a directory or a .jar file but it is not either of those?";
logger.error(msg);
logger.error("Error: expected classPath entry [" + element+ "] to be a directory or a .jar file but it is not either of those?");
}
}
if (matchList.isEmpty()) {
String msg = "No Entities found in ClassPath using ClassPathReader [" + classPathReader + "] Classpath Searched["
+ Arrays.toString(classPaths) + "]";
logger.warn(msg);
logger.warn("No Entities found in ClassPath using ClassPathReader [" + classPathReader + "] Classpath Searched[" + classPath + "]");
}
return matchList;
}
private ClassPathElement getClassPathElement(Object classPathEntry) {
private ClassPathElement getClassPathElement(Object classPathEntry) throws MalformedURLException {
if (!URL.class.isInstance(classPathEntry)) {
URL fileUrl = null;
if (URI.class.isInstance(classPathEntry)) {
fileUrl = ((URI)classPathEntry).toURL();
} else if (!URL.class.isInstance(classPathEntry)) {
// assumed to be a file path
return new ClassPathElement(classPathEntry.toString());
} else {
fileUrl = (URL) classPathEntry;
}
URL fileUrl = (URL) classPathEntry;
if (!fileUrl.getPath().contains("!")) {
return new ClassPathElement(new File(fileUrl.getFile()));
}
@@ -371,6 +382,34 @@ public class ClassPathSearch {
}
}
/**
* If URL and actually a jarfile with manifest return the derived classpath.
*/
private static List<URI> getClassPathFromManifest(Object classPathElement) {
try {
if (classPathElement instanceof URL) {
File file = new File(((URL)classPathElement).getFile());
if (file.isDirectory()) {
return Collections.emptyList();
}
JarFile jarFile = new JarFile(file);
try {
return getClassPathFromManifest(file, jarFile.getManifest());
} finally {
jarFile.close();
}
}
return Collections.emptyList();
} catch (IOException e) {
return Collections.emptyList();
}
}
/**
* If a jarfile with a manifest claspath return that.
*/
private static List<URI> getClassPathFromManifest(File jarFile, Manifest manifest) {
if (manifest == null) {
@@ -11,11 +11,11 @@ public class ClassPathSearchFilter {
private static final String COM_AVAJE_EBEANINTERNAL_SERVER_BEAN = "com.avaje.ebeaninternal.server.bean";
private static final String COM_AVAJE_EBEAN_META = "com.avaje.ebean.meta";
private static final String COM_AVAJE_EBEAN_META = "com.avaje.ebean.meta";
private boolean defaultPackageMatch = true;
private boolean defaultPackageMatch = true;
private boolean defaultJarMatch = true;
private boolean defaultJarMatch = false;
private String ebeanJarPrefix = "ebean";
@@ -121,7 +121,7 @@ public class ClassPathSearchFilter {
* Add a jar to explicitly exclude in the search.
*/
public void excludeJar(String jarName) {
includeJarSet.add(jarName);
excludeJarSet.add(jarName);
}
/**
@@ -129,7 +129,6 @@ public class ClassPathSearchFilter {
*/
public void includeJar(String jarName) {
includeJarSet.add(jarName);
}
/**
@@ -0,0 +1,48 @@
package com.avaje.tests.cascade;
import javax.persistence.OptimisticLockException;
import junit.framework.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.basic.TSDetail;
import com.avaje.tests.model.basic.TSMaster;
public class TestPrivateOwnedIgnoreTransientOrphan extends BaseTestCase {
@Test
public void test(){
/** new object **/
TSMaster master0 = new TSMaster();
/** recovered after first save **/
TSMaster master1 = null;
/** recovered after transient child ignored **/
TSMaster master2 = null;
Ebean.save(master0);
master1 = Ebean.find(master0.getClass(), master0.getId());
// Add then remove a bean that was never saved (to the DB)
master1.getDetails().add(new TSDetail());
master1.getDetails().clear();
try{
Ebean.save(master1);
} catch (OptimisticLockException exception) {
// Occured when the "unsaved" bean was wrongly being deleted
Assert.fail("Optimistic lock exception wrongly thrown: " + exception.getMessage());
return;
}
master2 = master1 = Ebean.find(master1.getClass(), master1.getId());
Assert.assertTrue(master2.getDetails().isEmpty());
}
}
@@ -2,6 +2,7 @@ package com.avaje.tests.model.basic;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@@ -14,7 +15,7 @@ public class UUTwo {
String name;
@ManyToOne
@ManyToOne(cascade=CascadeType.PERSIST)
UUOne master;
public UUID getId() {
@@ -0,0 +1,10 @@
package com.avaje.tests.model.inheritexposedtype;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue( "photo" )
public class IXPhoto extends IXResource {
}
@@ -0,0 +1,46 @@
package com.avaje.tests.model.inheritexposedtype;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class IXResource {
@Id
UUID id;
@Column(insertable=false, updatable=false)
String dtype;
String name;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getDtype() {
return dtype;
}
public void setDtype(String dtype) {
this.dtype = dtype;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,26 @@
package com.avaje.tests.model.inheritexposedtype.test;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.inheritexposedtype.IXPhoto;
public class TestInheritExposeDtype extends BaseTestCase {
@Test
public void test() {
IXPhoto p = new IXPhoto();
p.setName("the name");
Ebean.save(p);
// update
p.setName("new name");
Ebean.save(p);
// delete
Ebean.delete(p);
}
}
@@ -0,0 +1,42 @@
package com.avaje.tests.model.inheritmany;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class IMRelated {
@Id
Long id;
String name;
@ManyToOne(optional=false)
IMRoot owner;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IMRoot getOwner() {
return owner;
}
public void setOwner(IMRoot owner) {
this.owner = owner;
}
}
@@ -0,0 +1,37 @@
package com.avaje.tests.model.inheritmany;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class IMRoot {
@Id
Long id;
@OneToMany(mappedBy="owner")
List<IMRelated> related;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<IMRelated> getRelated() {
return related;
}
public void setRelated(List<IMRelated> related) {
this.related = related;
}
}
@@ -0,0 +1,20 @@
package com.avaje.tests.model.inheritmany;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue("ONE")
public class IMRootOne extends IMRoot {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,32 @@
package com.avaje.tests.model.inheritmany;
import java.util.Date;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue("TWO")
public class IMRootTwo extends IMRoot {
String title;
Date whenTitle;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getWhenTitle() {
return whenTitle;
}
public void setWhenTitle(Date whenTitle) {
this.whenTitle = whenTitle;
}
}
@@ -0,0 +1,29 @@
package com.avaje.tests.query.other;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.Expression;
import com.avaje.ebean.Query;
import com.avaje.tests.model.basic.Customer;
public class TestSubQueryBinding extends BaseTestCase {
@Test
public void test() {
EbeanServer server = Ebean.getServer(null);
Query<Customer> someCustomerIds = server.find(Customer.class).select("id").where().lt("id", 5).query();
Expression someCustIdsExpression = server.getExpressionFactory().in("id", someCustomerIds);
Query<Customer> query = server.find(Customer.class).where().like("name", "Rob%").not(someCustIdsExpression).query();
query.findList();
}
}
@@ -0,0 +1,67 @@
package com.avaje.tests.update;
import org.junit.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonWriteOptions;
import com.avaje.tests.model.basic.UUOne;
import com.avaje.tests.model.basic.UUTwo;
public class TestJsonStatelessUpdate extends BaseTestCase {
@Test
public void test() {
UUOne one = new UUOne();
one.setName("oneName");
Ebean.save(one);
UUTwo two = new UUTwo();
two.setMaster(one);
two.setName("twoName");
Ebean.save(two);
UUTwo twoX = Ebean.find(UUTwo.class, two.getId());
JsonContext jsonContext = Ebean.createJsonContext();
JsonWriteOptions writeOptions = JsonWriteOptions.parsePath("(id,name,master(*))");
String jsonString = jsonContext.toJsonString(twoX, true, writeOptions);
System.out.println(jsonString);
jsonString = jsonString.replace("twoName", "twoNameModified");
jsonString = jsonString.replace("oneName", "oneNameModified");
UUTwo two2 = jsonContext.toBean(UUTwo.class, jsonString);
Assert.assertEquals(twoX.getId(), two2.getId());
Assert.assertEquals("twoNameModified", two2.getName());
Assert.assertEquals("oneNameModified", two2.getMaster().getName());
// The update below cascades to also save "master" and that fails
// as it thinks it should INSERT master rather than UPDATE master
// Ebean.update(two2);
// The following is a workaround, to explicitly update master first
// so then Ebean doesn't try to save it when two2 is updated
Ebean.beginTransaction();
try {
UUOne master = two2.getMaster();
Ebean.update(master);
Ebean.update(two2);
} finally {
Ebean.endTransaction();
}
}
}
@@ -0,0 +1,73 @@
package org.avaje.test.model.inheritmany.test;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.tests.model.inheritmany.IMRelated;
import com.avaje.tests.model.inheritmany.IMRoot;
import com.avaje.tests.model.inheritmany.IMRootOne;
import com.avaje.tests.model.inheritmany.IMRootTwo;
public class TestInheritWithMany extends BaseTestCase {
@Test
public void test() {
EbeanServer server = Ebean.getServer(null);
Assert.assertNotNull(server);
SpiEbeanServer spiServer = (SpiEbeanServer)server;
BeanDescriptor<IMRoot> beanDescriptor = spiServer.getBeanDescriptor(IMRoot.class);
InheritInfo inheritInfo = beanDescriptor.getInheritInfo();
Assert.assertNotNull(inheritInfo);
IMRootOne one = new IMRootOne();
one.setName("One Name");
server.save(one);
add(one, "aaa");
add(one, "bbb");
IMRootTwo two = new IMRootTwo();
two.setTitle("Two Title");
server.save(two);
add(two, "ccc");
add(two, "ddd");
List<IMRoot> list = server.find(IMRoot.class).select("id").findList();
for (IMRoot imRoot : list) {
// lazy load the related OneToMany which is related to a non-leaf
List<IMRelated> related = imRoot.getRelated();
for (IMRelated imRelated : related) {
imRelated.getName();
}
}
}
private void add(IMRoot owner, String string) {
IMRelated relate = new IMRelated();
relate.setName(string);
relate.setOwner(owner);
EbeanServer server = Ebean.getServer(null);
server.save(relate);
}
}