mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
249cc5df49 | ||
|
|
2646e8c27f | ||
|
|
3eaf47fd70 | ||
|
|
9d64352771 | ||
|
|
aa7325b249 | ||
|
|
2839434773 | ||
|
|
de9823b69b | ||
|
|
15cab24848 | ||
|
|
b87e360ac7 | ||
|
|
82e68d7756 | ||
|
|
0371043914 | ||
|
|
54b5684628 | ||
|
|
da95ec0c05 | ||
|
|
b5eec93995 | ||
|
|
fc26765a7e | ||
|
|
9a6d339449 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.22.7</version>
|
||||
<version>11.22.9</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.22.7</tag>
|
||||
<tag>ebean-11.22.9</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
|
||||
@@ -98,6 +98,11 @@ public interface SqlUpdate {
|
||||
/**
|
||||
* Execute the update returning the number of rows modified.
|
||||
* <p>
|
||||
* Note that if the transaction has batch mode on then this update will use JDBC batch and may not execute until
|
||||
* later - at commit time or a transaction flush. In this case this method returns -1 indicating that the
|
||||
* update has been batched for later execution.
|
||||
* </p>
|
||||
* <p>
|
||||
* After you have executed the SqlUpdate you can bind new variables using
|
||||
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
|
||||
* again.
|
||||
@@ -112,6 +117,11 @@ public interface SqlUpdate {
|
||||
*/
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Execute the statement now regardless of the JDBC batch mode of the transaction.
|
||||
*/
|
||||
int executeNow();
|
||||
|
||||
/**
|
||||
* Execute when addBatch() has been used to batch multiple bind executions.
|
||||
*
|
||||
|
||||
@@ -312,4 +312,8 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
*/
|
||||
int[] executeBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql update regardless of transaction batch mode.
|
||||
*/
|
||||
int executeNow(SpiSqlUpdate sqlUpdate);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ import java.util.List;
|
||||
*/
|
||||
public class DefaultDbMigration implements DbMigration {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DefaultDbMigration.class);
|
||||
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.GenerateMigration");
|
||||
|
||||
private static final String initialVersion = "1.0";
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ public class ModelBuildElementTable {
|
||||
|
||||
VisitAllUsing.visitOne(targetDescriptor, new ModelBuildPropertyVisitor(ctx, table, targetDescriptor));
|
||||
|
||||
ctx.fkeyBuilder(table)
|
||||
.addForeignKey(manyProp.getBeanDescriptor(), manyProp.getTableJoin(), true);
|
||||
|
||||
ctx.addTable(table);
|
||||
}
|
||||
|
||||
|
||||
@@ -2054,6 +2054,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return persister.executeSqlUpdate(updSql, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow(SpiSqlUpdate sqlUpdate) {
|
||||
return persister.executeSqlUpdateNow(sqlUpdate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
|
||||
persister.addBatch(sqlUpdate, transaction);
|
||||
|
||||
@@ -133,6 +133,15 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
if (server != null) {
|
||||
return server.executeNow(this);
|
||||
} else {
|
||||
throw new IllegalStateException("server is null?");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() {
|
||||
if (server == null) {
|
||||
|
||||
@@ -8,6 +8,9 @@ import io.ebeaninternal.server.persist.BatchPostExecute;
|
||||
import io.ebeaninternal.server.persist.BatchedSqlException;
|
||||
import io.ebeaninternal.server.persist.PersistExecute;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Wraps all the objects used to persist a bean.
|
||||
*/
|
||||
@@ -95,6 +98,13 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
return transaction.isBatchThisRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the SQLException into a specific exception given the platform.
|
||||
*/
|
||||
public PersistenceException translateSqlException(SQLException e) {
|
||||
return transaction.translate(e.getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanManager;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import io.ebeaninternal.server.persist.BatchControl;
|
||||
@@ -131,6 +132,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
private boolean[] dirtyProperties;
|
||||
|
||||
/**
|
||||
* Imported OneToOne orphan that needs to be deleted.
|
||||
*/
|
||||
private EntityBean orphanBean;
|
||||
|
||||
/**
|
||||
* Flag set when request is added to JDBC batch.
|
||||
*/
|
||||
@@ -1377,4 +1383,19 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
changeSet.addBeanUpdate(beanDescriptor, idValue, changes, updateNaturalKey, getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an orphan bean that needs to be deleted AFTER the request has persisted.
|
||||
*/
|
||||
public void setImportedOrphanForRemoval(BeanPropertyAssocOne<?> prop) {
|
||||
Object orphan = getOrigValue(prop);
|
||||
if (orphan instanceof EntityBean) {
|
||||
orphanBean = (EntityBean)orphan;
|
||||
}
|
||||
}
|
||||
|
||||
public EntityBean getImportedOrphanForRemoval() {
|
||||
return orphanBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,18 +28,23 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
|
||||
private boolean addBatch;
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*/
|
||||
private boolean forceNoBatch;
|
||||
|
||||
public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
|
||||
SpiTransaction t, PersistExecute persistExecute) {
|
||||
SpiTransaction t, PersistExecute persistExecute, boolean forceNoBatch) {
|
||||
|
||||
super(server, t, persistExecute, sqlUpdate.getLabel());
|
||||
this.type = Type.UPDATESQL;
|
||||
this.updateSql = sqlUpdate;
|
||||
this.forceNoBatch = forceNoBatch;
|
||||
updateSql.reset();
|
||||
}
|
||||
|
||||
public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
|
||||
SpiTransaction t, PersistExecute persistExecute) {
|
||||
this(server, sqlUpdate, t, persistExecute, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profile(long offset, int flushCount) {
|
||||
profileBase(EVT_UPDATESQL, offset, (short)0, flushCount);
|
||||
@@ -60,7 +65,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
|
||||
@Override
|
||||
public boolean isBatchThisRequest() {
|
||||
return addBatch || super.isBatchThisRequest();
|
||||
return !forceNoBatch && (addBatch || super.isBatchThisRequest());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -74,10 +74,15 @@ public interface Persister {
|
||||
int executeOrmUpdate(Update<?> update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the UpdateSql.
|
||||
* Execute the SqlUpdate (taking into account transaction batch mode).
|
||||
*/
|
||||
int executeSqlUpdate(SqlUpdate update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the SqlUpdate now regardless of transaction batch mode.
|
||||
*/
|
||||
int executeSqlUpdateNow(SpiSqlUpdate update, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the CallableSql.
|
||||
*/
|
||||
|
||||
@@ -229,6 +229,8 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
if (!"".equals(propAnn.mappedBy())) {
|
||||
prop.setOneToOneExported();
|
||||
prop.setOrphanRemoval(propAnn.orphanRemoval());
|
||||
} else if (propAnn.orphanRemoval()) {
|
||||
prop.setOrphanRemoval(true);
|
||||
}
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo());
|
||||
|
||||
@@ -137,7 +137,7 @@ public final class DefaultPersister implements Persister {
|
||||
try {
|
||||
return batchControl.execute(sqlUpdate.getSql(), sqlUpdate.isGetGeneratedKeys());
|
||||
} catch (SQLException e) {
|
||||
throw new PersistenceException(e);
|
||||
throw transaction.translate(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,11 @@ public final class DefaultPersister implements Persister {
|
||||
return executeOrQueue(new PersistRequestUpdateSql(server, (SpiSqlUpdate) updSql, (SpiTransaction) t, persistExecute));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeSqlUpdateNow(SpiSqlUpdate updSql, Transaction t) {
|
||||
return executeOrQueue(new PersistRequestUpdateSql(server, updSql, (SpiTransaction) t, persistExecute, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore draft beans to match live beans given the query.
|
||||
*/
|
||||
@@ -896,6 +901,11 @@ public final class DefaultPersister implements Persister {
|
||||
BeanDescriptor<?> desc = request.getBeanDescriptor();
|
||||
SpiTransaction t = request.getTransaction();
|
||||
|
||||
EntityBean orphanForRemoval = request.getImportedOrphanForRemoval();
|
||||
if (orphanForRemoval != null) {
|
||||
delete(orphanForRemoval, request.getTransaction(), true);
|
||||
}
|
||||
|
||||
// exported ones with cascade save
|
||||
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneExportedSave()) {
|
||||
// check for partial beans
|
||||
@@ -1092,6 +1102,10 @@ public final class DefaultPersister implements Persister {
|
||||
// imported ones with save cascade
|
||||
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneImportedSave()) {
|
||||
// check for partial objects
|
||||
if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) {
|
||||
request.setImportedOrphanForRemoval(prop);
|
||||
}
|
||||
|
||||
if (request.isLoadedProperty(prop)) {
|
||||
EntityBean detailBean = prop.getValueAsEntityBean(request.getEntityBean());
|
||||
if (detailBean != null
|
||||
@@ -1108,14 +1122,18 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneExportedSave()) {
|
||||
if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) {
|
||||
Object origValue = request.getOrigValue(prop);
|
||||
if (origValue instanceof EntityBean) {
|
||||
delete((EntityBean) origValue, request.getTransaction(), true);
|
||||
}
|
||||
deleteOrphan(request, prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteOrphan(PersistRequestBean<?> request, BeanPropertyAssocOne<?> prop) {
|
||||
Object origValue = request.getOrigValue(prop);
|
||||
if (origValue instanceof EntityBean) {
|
||||
delete((EntityBean) origValue, request.getTransaction(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for loading any Imported Associated One properties that are not
|
||||
* loaded but required for Delete cascade.
|
||||
|
||||
@@ -48,7 +48,7 @@ class ExeCallableSql {
|
||||
}
|
||||
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
throw request.translateSqlException(ex);
|
||||
|
||||
} finally {
|
||||
if (!batchThisRequest) {
|
||||
|
||||
@@ -55,8 +55,8 @@ class ExeUpdateSql {
|
||||
request.postExecute();
|
||||
return rowCount;
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
} catch (SQLException e) {
|
||||
throw request.translateSqlException(e);
|
||||
|
||||
} finally {
|
||||
if (!batchThisRequest) {
|
||||
|
||||
@@ -148,7 +148,10 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
public ScalarType<?> getSingleAttributeScalarType() {
|
||||
if (properties == null || properties.length == 0) {
|
||||
// if we have no property ask first children (in a distinct select with join)
|
||||
// if we have also no children, NPE happens anyway.
|
||||
if (children.length == 0) {
|
||||
// expected to be a findIds query
|
||||
return desc.getIdBinder().getBeanProperty().getScalarType();
|
||||
}
|
||||
return children[0].getSingleAttributeScalarType();
|
||||
}
|
||||
if (properties[0] instanceof STreePropertyAssocOne) {
|
||||
|
||||
@@ -769,6 +769,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
copy.mapKey = mapKey;
|
||||
copy.id = id;
|
||||
copy.label = label;
|
||||
copy.nativeSql = nativeSql;
|
||||
copy.useBeanCache = useBeanCache;
|
||||
copy.useQueryCache = useQueryCache;
|
||||
copy.readOnly = readOnly;
|
||||
@@ -1050,7 +1051,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
CQueryPlanKey createQueryPlanKey() {
|
||||
|
||||
if (isNativeSql()) {
|
||||
queryPlanKey = new NativeSqlQueryPlanKey(nativeSql + "-" + firstRow + "-" + maxRows);
|
||||
queryPlanKey = new NativeSqlQueryPlanKey(type.ordinal() + nativeSql + "-" + firstRow + "-" + maxRows);
|
||||
} else {
|
||||
queryPlanKey = new OrmQueryPlanKey(planDescription(), maxRows, firstRow, rawSql);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ create or replace function _partition_create(meta partition_meta, extra text)
|
||||
language plpgsql
|
||||
set timezone to 'UTC'
|
||||
as $$
|
||||
declare
|
||||
idx_col text;
|
||||
idx_name text;
|
||||
begin
|
||||
|
||||
execute format('create table if not exists %I partition of %I for values from (''%s'') TO (''%s'')', meta.part_name, meta.base_name, meta.period_start, meta.period_end);
|
||||
@@ -45,7 +48,12 @@ begin
|
||||
end if;
|
||||
|
||||
if (length(meta.index_column) > 0) then
|
||||
execute format('create index if not exists ix_%I_%s ON %I (%I)', meta.part_name, meta.index_column, meta.part_name, meta.index_column);
|
||||
-- delimited for multiple indexes
|
||||
foreach idx_col in array regexp_split_to_array(meta.index_column,';')
|
||||
loop
|
||||
idx_name = replace(idx_col, ',', '_');
|
||||
execute format('create index if not exists ix_%I_%s ON %I (%s)', meta.part_name, idx_name, meta.part_name, idx_col);
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
if (length(extra) > 0) then
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.ebean.meta.MetaOrmQueryMetric;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Country;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.EBasicWithUniqueCon;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
@@ -42,6 +43,32 @@ public class UpdateQueryTest extends BaseTestCase {
|
||||
assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateActive");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update_withTransactionBatch() {
|
||||
|
||||
EbeanServer server = server();
|
||||
|
||||
try (Transaction transaction = server.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
UpdateQuery<Customer> update = server.update(Customer.class);
|
||||
|
||||
Query<Customer> query = update
|
||||
.set("status", Customer.Status.ACTIVE)
|
||||
.set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
.where()
|
||||
.eq("status", Customer.Status.NEW)
|
||||
.gt("id", 99999)
|
||||
.query();
|
||||
|
||||
// update executes now regardless of transaction batch mode
|
||||
int rows = query.update();
|
||||
assertThat(rows).isEqualTo(0);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnorePlatform(Platform.SQLSERVER)
|
||||
public void withTableAlias() {
|
||||
@@ -199,4 +226,27 @@ public class UpdateQueryTest extends BaseTestCase {
|
||||
|
||||
assertThat(rows).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void exceptionTranslation() {
|
||||
|
||||
newEbasicWithUnique("o1","other1_a");
|
||||
Integer id = newEbasicWithUnique("o2", "other1_b");
|
||||
|
||||
Ebean.update(EBasicWithUniqueCon.class)
|
||||
.set("other", "other1_a")
|
||||
.set("otherOne", "other1_a")
|
||||
.where().idEq(id)
|
||||
.update();
|
||||
}
|
||||
|
||||
private Integer newEbasicWithUnique(String name, String other) {
|
||||
EBasicWithUniqueCon b0 = new EBasicWithUniqueCon();
|
||||
b0.setName(name);
|
||||
b0.setOther(other);
|
||||
b0.setOtherOne(other);
|
||||
Ebean.save(b0);
|
||||
|
||||
return b0.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,6 +854,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow(SpiSqlUpdate sqlUpdate) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.tests.cache;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import org.tests.model.basic.Country;
|
||||
import org.tests.model.basic.OCachedBean;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
@@ -41,4 +42,15 @@ public class TestBeanCache extends BaseTestCase {
|
||||
assertThat(sql).isEmpty();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void find_whenNotExits() {
|
||||
|
||||
Country country = Ebean.find(Country.class)
|
||||
.where()
|
||||
.eq("name","NotValid")
|
||||
.findOne();
|
||||
|
||||
assertThat(country).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,38 @@ public class TestOneToOneOrphanStringId extends BaseTestCase {
|
||||
assertThat(deletes.get(0)).contains("delete from oto_atwo");
|
||||
assertThat(deletes.get(1)).contains("delete from oto_aone");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_remove() {
|
||||
|
||||
OtoAtwo b = new OtoAtwo("b3", "b test");
|
||||
Ebean.save(b);
|
||||
|
||||
OtoAone a = new OtoAone("a3", "a test");
|
||||
b.setAone(a);
|
||||
|
||||
Ebean.save(b);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
OtoAone a2 = new OtoAone("a4", "a test");
|
||||
b.setAone(a2);
|
||||
Ebean.save(b);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.current();
|
||||
assertThat(sql).hasSize(3);
|
||||
assertThat(sql.get(0)).contains("insert into oto_aone");
|
||||
assertThat(sql.get(1)).contains("update oto_atwo set aone_id=? where id=?");
|
||||
assertThat(sql.get(2)).contains("delete from oto_aone where id=?");
|
||||
|
||||
Ebean.delete(b);
|
||||
|
||||
List<String> deletes = LoggedSqlCollector.stop();
|
||||
assertThat(deletes).hasSize(2);
|
||||
assertThat(deletes.get(0)).contains("delete from oto_atwo");
|
||||
assertThat(deletes.get(1)).contains("delete from oto_aone");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.tests.query;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.PagedList;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Contact;
|
||||
import org.tests.model.basic.Customer;
|
||||
@@ -13,6 +16,114 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class TestQueryFindNative extends BaseTestCase {
|
||||
|
||||
|
||||
@Test
|
||||
public void findCount() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
String sql = "select n.id from contact n where n.first_name like ?";
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int rowCount = server()
|
||||
.findNative(Contact.class, sql)
|
||||
.setParameter(1, "J%")
|
||||
.findCount();
|
||||
|
||||
List<Integer> nativeIds =
|
||||
server()
|
||||
.findNative(Contact.class, sql)
|
||||
.setParameter(1, "J%")
|
||||
.findIds();
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(nativeIds).hasSize(rowCount);
|
||||
|
||||
assertThat(loggedSql).hasSize(2);
|
||||
assertThat(loggedSql.get(0)).contains("select count(*) from ( select n.id from contact n where n.first_name like ?)");
|
||||
assertThat(loggedSql.get(1)).startsWith("select n.id from contact n where n.first_name like ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findPagedList() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
String sql = "select n.id, n.first_name from contact n where n.first_name like ?";
|
||||
|
||||
PagedList<Contact> pagedList = server()
|
||||
.findNative(Contact.class, sql)
|
||||
.setParameter(1, "J%")
|
||||
.setMaxRows(100)
|
||||
.findPagedList();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int listSize = pagedList.getList().size();
|
||||
int totalCount = pagedList.getTotalCount();
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(listSize).isEqualTo(totalCount);
|
||||
|
||||
assertThat(loggedSql).hasSize(2);
|
||||
assertThat(loggedSql.get(0)).startsWith("select n.id, n.first_name from contact n where n.first_name like ?");
|
||||
assertThat(loggedSql.get(1)).contains("select count(*) from ( select n.id, n.first_name from contact n where n.first_name like ?)");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void findPagedList_withColumnAlias() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
String sql = "select n.id, 'SillyName' first_name from contact n where n.id < ? ";
|
||||
|
||||
PagedList<Contact> pagedList = server()
|
||||
.findNative(Contact.class, sql)
|
||||
.setParameter(1, 100)
|
||||
.setMaxRows(100)
|
||||
.findPagedList();
|
||||
|
||||
int listSize = pagedList.getList().size();
|
||||
int totalCount = pagedList.getTotalCount();
|
||||
|
||||
assertThat(listSize).isEqualTo(totalCount);
|
||||
|
||||
for (Contact contact : pagedList.getList()) {
|
||||
assertThat(contact.getFirstName()).isEqualTo("SillyName");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void findIds() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
String sql = "select c.id from contact c where c.first_name like ? ";
|
||||
|
||||
List<Integer> ids = Ebean.createSqlQuery(sql)
|
||||
.setParameter(1, "J%")
|
||||
.findSingleAttributeList(Integer.class);
|
||||
|
||||
List<Integer> idsScalar =
|
||||
server()
|
||||
.findNative(Contact.class, sql)
|
||||
.setParameter(1, "J%")
|
||||
.findSingleAttributeList();
|
||||
|
||||
List<Integer> nativeIds =
|
||||
server()
|
||||
.findNative(Contact.class, sql)
|
||||
.setParameter(1, "J%")
|
||||
.findIds();
|
||||
|
||||
|
||||
assertThat(nativeIds).isNotEmpty();
|
||||
assertThat(nativeIds).containsAll(ids);
|
||||
assertThat(idsScalar).containsAll(ids);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void joinFromManyToOne() {
|
||||
|
||||
|
||||
@@ -14,9 +14,48 @@ import org.tests.model.softdelete.EBasicSoftDelete;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TestSoftDeleteBasic extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testCascadeSaveDelete_other() {
|
||||
|
||||
EBasicSoftDelete bean = new EBasicSoftDelete();
|
||||
bean.setName("cascadeOne");
|
||||
bean.addChild("child1", 10);
|
||||
bean.addChild("child2", 20);
|
||||
bean.addChild("child3", 30);
|
||||
bean.addNoSoftDeleteChild("nsd1", 101);
|
||||
bean.addNoSoftDeleteChild("nsd2", 102);
|
||||
|
||||
Ebean.save(bean);
|
||||
|
||||
assertEquals(new Long(1), bean.getVersion());
|
||||
assertEquals(new Long(1), bean.getChildren().get(0).getVersion());
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.delete(bean);
|
||||
|
||||
// List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
//
|
||||
// assertEquals(new Long(2), bean.getVersion());
|
||||
// assertEquals(new Long(2), bean.getChildren().get(0).getVersion()); // Fails with 1
|
||||
//
|
||||
// // The children without SoftDelete are left as is (so no third statement)
|
||||
// assertThat(loggedSql).hasSize(2);
|
||||
//
|
||||
// // first statement is a single bulk update of the children with SoftDelete
|
||||
// assertThat(loggedSql.get(0)).contains("update ebasic_sdchild set deleted=");
|
||||
// assertThat(loggedSql.get(0)).contains("where owner_id = ?");
|
||||
//
|
||||
// // second statement is the top level bean
|
||||
// assertThat(loggedSql.get(1)).contains(
|
||||
// "update ebasic_soft_delete set version=?, deleted=? where id=? and version=?");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindIdsWhenIncludeSoftDeletedChlld() {
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.tests.update;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DuplicateKeyException;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class TestSqlUpdateExceptions extends BaseTestCase {
|
||||
|
||||
private String sql = "insert into uuone (id, name, version) values (?,?,?)";
|
||||
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void duplicateKey() {
|
||||
|
||||
UUID id = UUID.randomUUID();
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "hi");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.execute();
|
||||
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "fail");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.execute();
|
||||
}
|
||||
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void duplicateKey_executeNow() {
|
||||
|
||||
|
||||
UUID id = UUID.randomUUID();
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "hi");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.executeNow();
|
||||
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "fail");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.executeNow();
|
||||
}
|
||||
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void duplicateKey_inBatch() {
|
||||
|
||||
UUID id = UUID.randomUUID();
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "hi in batch");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.addBatch();
|
||||
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "fail in batch");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.addBatch();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = DuplicateKeyException.class)
|
||||
public void duplicateKey_executeBatch() {
|
||||
|
||||
UUID id = UUID.randomUUID();
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "hi in batch");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.addBatch();
|
||||
|
||||
sqlUpdate.setParameter(1, id);
|
||||
sqlUpdate.setParameter(2, "fail in batch");
|
||||
sqlUpdate.setParameter(3, 1);
|
||||
sqlUpdate.addBatch();
|
||||
int[] ints = sqlUpdate.executeBatch();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.tests.update;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@@ -38,6 +39,41 @@ public class TestSqlUpdateInTxn extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute_inTransaction_withBatch() {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
int row = Ebean.createSqlUpdate("update audit_log set description = description where id = ?")
|
||||
.setParameter(1, 999999)
|
||||
.execute();
|
||||
|
||||
// update statement using JDBC batch so not executed yet
|
||||
assertThat(row).isEqualTo(-1);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteNow_inTransaction_withBatch() {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
int row = Ebean.createSqlUpdate("update audit_log set description = description where id = ?")
|
||||
.setParameter(1, 999999)
|
||||
.executeNow();
|
||||
|
||||
// update statement executed even though JDBC batch mode is on
|
||||
assertThat(row).isEqualTo(0);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSqlUpdateWithWhitespace() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user