[hibernate-commits] Hibernate SVN: r11459 - in trunk/HibernateExt/shards/src: java/org/hibernate/shards/session and 3 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Wed May 2 03:38:01 EDT 2007
Author: max.ross
Date: 2007-05-02 03:38:01 -0400 (Wed, 02 May 2007)
New Revision: 11459
Added:
trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelIntegrationTest.java
Modified:
trunk/HibernateExt/shards/src/java/org/hibernate/shards/Shard.java
trunk/HibernateExt/shards/src/java/org/hibernate/shards/ShardImpl.java
trunk/HibernateExt/shards/src/java/org/hibernate/shards/session/ShardedSessionImpl.java
trunk/HibernateExt/shards/src/test/org/hibernate/shards/NonPermutedTests.java
trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelPermutedIntegrationTest.java
trunk/HibernateExt/shards/src/test/org/hibernate/shards/session/ShardedSessionImplTest.java
Log:
Fix bugs in update, delete, and saveOrUpdate.
Add support for objects with ids that are base types.
Modified: trunk/HibernateExt/shards/src/java/org/hibernate/shards/Shard.java
===================================================================
--- trunk/HibernateExt/shards/src/java/org/hibernate/shards/Shard.java 2007-05-02 06:23:27 UTC (rev 11458)
+++ trunk/HibernateExt/shards/src/java/org/hibernate/shards/Shard.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -18,6 +18,11 @@
package org.hibernate.shards;
+import org.hibernate.Criteria;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.classic.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.shards.criteria.CriteriaEvent;
import org.hibernate.shards.criteria.CriteriaId;
import org.hibernate.shards.criteria.ShardedCriteria;
@@ -26,12 +31,6 @@
import org.hibernate.shards.query.ShardedQuery;
import org.hibernate.shards.session.OpenSessionEvent;
-import org.hibernate.Criteria;
-import org.hibernate.LockMode;
-import org.hibernate.Query;
-import org.hibernate.classic.Session;
-import org.hibernate.engine.SessionFactoryImplementor;
-
import java.io.Serializable;
import java.util.List;
import java.util.Set;
@@ -188,4 +187,8 @@
* @see Query#uniqueResult()
*/
Object uniqueResult(QueryId queryId);
+
+ void merge(Object object);
+
+ void merge(String entityName, Object object);
}
Modified: trunk/HibernateExt/shards/src/java/org/hibernate/shards/ShardImpl.java
===================================================================
--- trunk/HibernateExt/shards/src/java/org/hibernate/shards/ShardImpl.java 2007-05-02 06:23:27 UTC (rev 11458)
+++ trunk/HibernateExt/shards/src/java/org/hibernate/shards/ShardImpl.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -18,6 +18,12 @@
package org.hibernate.shards;
+import org.hibernate.Criteria;
+import org.hibernate.Interceptor;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.classic.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.shards.criteria.CriteriaEvent;
import org.hibernate.shards.criteria.CriteriaId;
import org.hibernate.shards.criteria.ShardedCriteria;
@@ -30,13 +36,6 @@
import org.hibernate.shards.util.Preconditions;
import org.hibernate.shards.util.Sets;
-import org.hibernate.Criteria;
-import org.hibernate.Interceptor;
-import org.hibernate.LockMode;
-import org.hibernate.Query;
-import org.hibernate.classic.Session;
-import org.hibernate.engine.SessionFactoryImplementor;
-
import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
@@ -382,5 +381,12 @@
events.addLast(event);
}
+ public void merge(Object object) {
+ establishSession().merge(object);
+ }
+
+ public void merge(String entityName, Object object) {
+ establishSession().merge(entityName, object);
+ }
}
Modified: trunk/HibernateExt/shards/src/java/org/hibernate/shards/session/ShardedSessionImpl.java
===================================================================
--- trunk/HibernateExt/shards/src/java/org/hibernate/shards/session/ShardedSessionImpl.java 2007-05-02 06:23:27 UTC (rev 11458)
+++ trunk/HibernateExt/shards/src/java/org/hibernate/shards/session/ShardedSessionImpl.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -18,14 +18,34 @@
package org.hibernate.shards.session;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.CacheMode;
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.Filter;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ReplicationMode;
+import org.hibernate.SQLQuery;
+import org.hibernate.SessionException;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.TransientObjectException;
+import org.hibernate.classic.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.proxy.HibernateProxy;
import org.hibernate.shards.CrossShardAssociationException;
import org.hibernate.shards.Shard;
import org.hibernate.shards.ShardId;
import org.hibernate.shards.ShardImpl;
import org.hibernate.shards.ShardOperation;
import org.hibernate.shards.ShardedTransaction;
-import org.hibernate.shards.util.Lists;
-import org.hibernate.shards.util.Sets;
import org.hibernate.shards.criteria.CriteriaFactoryImpl;
import org.hibernate.shards.criteria.CriteriaId;
import org.hibernate.shards.criteria.ShardedCriteriaImpl;
@@ -43,32 +63,11 @@
import org.hibernate.shards.strategy.selection.ShardResolutionStrategyDataImpl;
import org.hibernate.shards.transaction.ShardedTransactionImpl;
import org.hibernate.shards.util.Iterables;
+import org.hibernate.shards.util.Lists;
import org.hibernate.shards.util.Maps;
import org.hibernate.shards.util.Pair;
import org.hibernate.shards.util.Preconditions;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hibernate.CacheMode;
-import org.hibernate.Criteria;
-import org.hibernate.EntityMode;
-import org.hibernate.Filter;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.Interceptor;
-import org.hibernate.LockMode;
-import org.hibernate.Query;
-import org.hibernate.ReplicationMode;
-import org.hibernate.SQLQuery;
-import org.hibernate.SessionException;
-import org.hibernate.SessionFactory;
-import org.hibernate.Transaction;
-import org.hibernate.TransientObjectException;
-import org.hibernate.classic.Session;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.id.IdentifierGenerator;
-import org.hibernate.metadata.ClassMetadata;
-import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.shards.util.Sets;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.type.Type;
@@ -579,16 +578,14 @@
}
public Serializable save(String entityName, Object object) throws HibernateException {
- ShardId shardId;
- if(contains(object)) {
- shardId = getShardIdForObject(object);
- } else {
+ ShardId shardId = getShardIdForObject(object);
+ if(shardId == null) {
shardId = selectShardIdForNewObject(object);
}
Preconditions.checkNotNull(shardId);
setCurrentSubgraphShardId(shardId);
log.debug(String.format("Saving object of type %s to shard %s", object.getClass(), shardId));
- return shardIdsToShards.get(shardId).save(entityName, object);
+ return shardIdsToShards.get(shardId).save(entityName, object);
}
ShardId selectShardIdForNewObject(Object obj) {
@@ -725,83 +722,112 @@
shard.saveOrUpdate(entityName, object);
}
- public void update(Shard shard, Object object) {
- shard.update(entityName, object);
+ public void merge(Shard shard, Object object) {
+ shard.merge(entityName, object);
}
};
applySaveOrUpdateOperation(op, object);
}
void applySaveOrUpdateOperation(SaveOrUpdateOperation op, Object object) {
- List<ShardId> saveOrUpdateShardIds = determineShardIdsForObjectThatMightAlreadyExist(object);
- if(saveOrUpdateShardIds.size() == 1) {
- /**
- * if there's only 1 shard id we don't need to worry about whether this is
- * a save or an update because we know we've got the right shard.
- * We'll let that shard figure out what the right thing to do is
- */
- ShardId shardId = saveOrUpdateShardIds.get(0);
- setCurrentSubgraphShardId(shardId);
+ ShardId shardId = getShardIdForObject(object);
+ if(shardId != null) {
+ // attached object
op.saveOrUpdate(shardIdsToShards.get(shardId), object);
- } else {
- /**
- * If we've got multiple shard ids we know it's an update. However,
- * we can't call saveOrUpdate() on multiple shards because if it
- * already exists and we call saveOrUpdate() on the wrong shard we're
- * going to end up with the same object in multiple shards, and that's
- * really bad. Instead we'll just figure out the single shard on which
- * the object resides and perform the update there.
- */
- ShardId shardId = getShardIdForObject(object);
- setCurrentSubgraphShardId(shardId);
- Shard shard = shardIdsToShards.get(shardId);
- op.update(shard, object);
+ return;
}
- }
+ List<Shard> potentialShards = determineShardsObjectViaResolutionStrategy(object);
+ if(potentialShards.size() == 1) {
+ op.saveOrUpdate(potentialShards.get(0), object);
+ return;
+ }
- List<ShardId> determineShardIdsForObjectThatMightAlreadyExist(Object object) {
+ /**
+ * Too bad, we've got a detached object that could be on more than 1 shard.
+ * The only safe way to handle this is to try and lookup the object, and if
+ * it exists, do a merge, and if it doesn't, do a save.
+ */
Serializable id = extractId(object);
- if(id == null) {
- ShardId shardId = selectShardIdForNewObject(object);
- // if there's no id then it's clearly a save operation
- return Collections.singletonList(shardId);
+ if(id != null) {
+ Object persistent = get(object.getClass(), id);
+ if(persistent != null) {
+ shardId = getShardIdForObject(persistent);
+ }
}
- /**
- * there is an id so it might be a save operation (user provided the id)
- * or it might be an update
- */
- ShardResolutionStrategyData srsd = new ShardResolutionStrategyDataImpl(object.getClass(), id);
- return selectShardIdsFromShardResolutionStrategyData(srsd);
+ if(shardId != null) {
+ op.merge(shardIdsToShards.get(shardId), object);
+ } else {
+ save(object);
+ }
}
- private Serializable extractId(Object object) {
+ Serializable extractId(Object object) {
ClassMetadata cmd = shardedSessionFactory.getClassMetadata(object.getClass());
// I'm just guessing about the EntityMode
return cmd.getIdentifier(object, EntityMode.POJO);
}
- public void update(Object object) throws HibernateException {
- /*
- * we might get back multiple shards if there isn't a sure-fire
- * way to derive the shard from the object, but since the object
- * only exists on one shard there's no harm in trying to update
- * it multiple places because the update will only succeed in one place.
+ private interface UpdateOperation {
+ void update(Shard shard, Object object);
+ void merge(Shard shard, Object object);
+ }
+
+ private static final UpdateOperation SIMPLE_UPDATE_OPERATION =
+ new UpdateOperation() {
+ public void update(Shard shard, Object object) {
+ shard.update(object);
+ }
+
+ public void merge(Shard shard, Object object) {
+ shard.merge(object);
+ }
+ };
+
+ private void applyUpdateOperation(UpdateOperation op, Object object) {
+ ShardId shardId = getShardIdForObject(object);
+ if(shardId != null) {
+ // attached object
+ op.update(shardIdsToShards.get(shardId), object);
+ return;
+ }
+ List<Shard> potentialShards = determineShardsObjectViaResolutionStrategy(object);
+ if(potentialShards.size() == 1) {
+ op.update(potentialShards.get(0), object);
+ return;
+ }
+ /**
+ * Too bad, we've got a detached object that could be on more than 1 shard.
+ * The only safe way to perform the update is to load the object and then
+ * do a merge.
*/
- // What about exceptions?
- for(Shard shard : determineShardsForObjectThatExists(object)) {
- shard.update(object);
- }
+ Object persistent = get(object.getClass(), extractId(object));
+ shardId = getShardIdForObject(persistent);
+ op.merge(shardIdsToShards.get(shardId), object);
}
- public void update(String entityName, Object object)
+ public void update(Object object) throws HibernateException {
+ applyUpdateOperation(SIMPLE_UPDATE_OPERATION, object);
+ }
+
+ public void update(final String entityName, Object object)
throws HibernateException {
- for(Shard shard : determineShardsForObjectThatExists(object)) {
- shard.update(entityName, object);
- }
+ UpdateOperation op = new UpdateOperation() {
+ public void update(Shard shard, Object object) {
+ shard.update(entityName, object);
+ }
+
+ public void merge(Shard shard, Object object) {
+ shard.merge(entityName, object);
+ }
+ };
+ applyUpdateOperation(op, object);
}
- private List<Shard> determineShardsForObjectThatExists(Object object) {
+ List<Shard> determineShardsObjectViaResolutionStrategy(Object object) {
Serializable id = extractId(object);
+ if(id == null) {
+ return Collections.emptyList();
+ }
ShardResolutionStrategyData srsd = new ShardResolutionStrategyDataImpl(object.getClass(), id);
List<ShardId> shardIds = selectShardIdsFromShardResolutionStrategyData(srsd);
return shardIdListToShardList(shardIds);
@@ -837,32 +863,63 @@
throw new UnsupportedOperationException();
}
- public void delete(Object object) throws HibernateException {
+ private interface DeleteOperation {
+ void delete(Shard shard, Object object);
+ }
+
+ private void applyDeleteOperation(DeleteOperation op, Object object) {
+ ShardId shardId = getShardIdForObject(object);
+ if(shardId != null) {
+ // attached object
+ op.delete(shardIdsToShards.get(shardId), object);
+ return;
+ }
/**
- * we might get back multiple shards if there isn't a sure-fire
- * way to derive the shard from the object. It turns out that if you have an
+ * Detached object.
+ * We can't just try to delete on each shard because if you have an
* object associated with Session x and you try to delete that object in
- * Sessoin y, and if that object has persistent collections, Hibernate will
+ * Session y, and if that object has persistent collections, Hibernate will
* blow up because it will try to associate the persistent collection with
* a different Session as part of the cascade. In order to avoid this we
- * need to be precise about the shard on which we perform the delete
+ * need to be precise about the shard on which we perform the delete.
+ *
+ * First let's see if we can derive the shard just from the object's id.
*/
-
- // What about exceptions?
- List<Shard> potentialShards = determineShardsForObjectThatExists(object);
+ List<Shard> potentialShards = determineShardsObjectViaResolutionStrategy(object);
if(potentialShards.size() == 1) {
- potentialShards.get(0).delete(object);
+ op.delete(potentialShards.get(0), object);
return;
}
- ShardId shardId = getShardIdForObject(object, potentialShards);
- shardIdsToShards.get(shardId).delete(object);
+ /**
+ * Too bad, we've got a detached object that could be on more than 1 shard.
+ * The only safe way to perform the delete is to load the object before
+ * deleting.
+ */
+ Object persistent = get(object.getClass(), extractId(object));
+ shardId = getShardIdForObject(persistent);
+ op.delete(shardIdsToShards.get(shardId), persistent);
}
- public void delete(String entityName, Object object)
+ private static final DeleteOperation SIMPLE_DELETE_OPERATION =
+ new DeleteOperation() {
+
+ public void delete(Shard shard, Object object) {
+ shard.delete(object);
+ }
+ };
+
+ public void delete(Object object) throws HibernateException {
+ applyDeleteOperation(SIMPLE_DELETE_OPERATION, object);
+ }
+
+ public void delete(final String entityName, Object object)
throws HibernateException {
- for(Shard shard : determineShardsForObjectThatExists(object)) {
- shard.delete(entityName, object);
- }
+ DeleteOperation op = new DeleteOperation() {
+ public void delete(Shard shard, Object object) {
+ shard.delete(entityName, object);
+ }
+ };
+ applyDeleteOperation(op, object);
}
/**
@@ -1258,7 +1315,7 @@
interface SaveOrUpdateOperation {
void saveOrUpdate(Shard shard, Object object);
- void update(Shard shard, Object object);
+ void merge(Shard shard, Object object);
}
private static final SaveOrUpdateOperation SAVE_OR_UPDATE_SIMPLE = new SaveOrUpdateOperation() {
@@ -1266,8 +1323,8 @@
shard.saveOrUpdate(object);
}
- public void update(Shard shard, Object object) {
- shard.update(object);
+ public void merge(Shard shard, Object object) {
+ shard.merge(object);
}
};
@@ -1293,6 +1350,7 @@
}
public ShardId getShardIdForObject(Object obj, List<Shard> shardsToConsider) {
+ // TODO(maxr) optimize this by keeping an identity map of objects to shardId
Shard shard = getShardForObject(obj, shardsToConsider);
if(shard == null) {
return null;
Modified: trunk/HibernateExt/shards/src/test/org/hibernate/shards/NonPermutedTests.java
===================================================================
--- trunk/HibernateExt/shards/src/test/org/hibernate/shards/NonPermutedTests.java 2007-05-02 06:23:27 UTC (rev 11458)
+++ trunk/HibernateExt/shards/src/test/org/hibernate/shards/NonPermutedTests.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -65,6 +65,7 @@
classes.add(org.hibernate.shards.id.ShardedTableHiLoGeneratorTest.class);
classes.add(org.hibernate.shards.id.ShardedUUIDGeneratorTest.class);
classes.add(org.hibernate.shards.integration.model.MemoryLeakTest.class);
+ classes.add(org.hibernate.shards.integration.model.ModelIntegrationTest.class);
classes.add(org.hibernate.shards.loadbalance.RoundRobinShardLoadBalancerTest.class);
classes.add(org.hibernate.shards.query.SetBigDecimalEventTest.class);
classes.add(org.hibernate.shards.query.SetBigIntegerEventTest.class);
Added: trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelIntegrationTest.java
===================================================================
--- trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelIntegrationTest.java (rev 0)
+++ trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelIntegrationTest.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2007 Google Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+package org.hibernate.shards.integration.model;
+
+import org.hibernate.shards.integration.BaseShardingIntegrationTestCase;
+import org.hibernate.shards.model.IdIsBaseType;
+
+/**
+ * @author maxr at google.com (Max Ross)
+ */
+public class ModelIntegrationTest extends BaseShardingIntegrationTestCase {
+
+ public void testSaveIdIsBaseType() {
+ IdIsBaseType hli = new IdIsBaseType();
+ session.beginTransaction();
+ hli.setValue("yamma");
+ session.save(hli);
+ commitAndResetSession();
+ hli = reload(hli);
+ assertNotNull(hli);
+ }
+
+ public void testSaveOrUpdateIdIsBasetype() {
+ IdIsBaseType hli = new IdIsBaseType();
+ session.beginTransaction();
+ hli.setValue("yamma");
+ session.saveOrUpdate(hli);
+ commitAndResetSession();
+ hli = reload(hli);
+ assertNotNull(hli);
+ }
+
+}
Modified: trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelPermutedIntegrationTest.java
===================================================================
--- trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelPermutedIntegrationTest.java 2007-05-02 06:23:27 UTC (rev 11458)
+++ trunk/HibernateExt/shards/src/test/org/hibernate/shards/integration/model/ModelPermutedIntegrationTest.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -18,6 +18,12 @@
package org.hibernate.shards.integration.model;
+import org.hibernate.HibernateException;
+import org.hibernate.SessionFactory;
+import org.hibernate.TransactionException;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Projections;
+import org.hibernate.proxy.HibernateProxy;
import org.hibernate.shards.ShardId;
import org.hibernate.shards.integration.BaseShardingIntegrationTestCase;
import org.hibernate.shards.integration.MemoryLeakPlugger;
@@ -46,13 +52,6 @@
import org.hibernate.shards.util.Maps;
import org.hibernate.shards.util.Sets;
-import org.hibernate.HibernateException;
-import org.hibernate.SessionFactory;
-import org.hibernate.TransactionException;
-import org.hibernate.classic.Session;
-import org.hibernate.criterion.Projections;
-import org.hibernate.proxy.HibernateProxy;
-
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
@@ -82,7 +81,7 @@
@Override
protected IdGenType getIdGenType() {
- return IdGenType.SHARD_UUID;
+ return IdGenType.SIMPLE;
}
*/
@@ -106,8 +105,7 @@
session.save(b);
buildings.add(b);
}
- session.getTransaction().commit();
- resetSession();
+ commitAndResetSession();
List<Integer> counts = session.createCriteria(Building.class).setProjection(Projections.rowCount()).list();
int total = 0;
for(Integer count : counts) {
@@ -150,8 +148,7 @@
for(List<Serializable> idList : shards.values()) {
assertEquals(2, idList.size());
}
- session.getTransaction().commit();
- resetSession();
+ commitAndResetSession();
session.beginTransaction();
for(Building b : buildings) {
Building bReloaded = reloadAssertNotNull(b);
@@ -169,8 +166,7 @@
// now let's get rid of the buildings
session.delete(bReloaded);
}
- session.getTransaction().commit();
- resetSession();
+ commitAndResetSession();
for(Building b : buildings) {
assertNull(reload(b));
for(Floor f : b.getFloors()) {
@@ -179,20 +175,36 @@
}
}
- public void testSaveOrUpdate() {
+ public void testSaveOrUpdateAttached() {
session.beginTransaction();
Building b = building("b");
floor(b, 23);
- session.save(b);
- session.getTransaction().commit();
- resetSession();
+ session.saveOrUpdate(b);
+ commitAndResetSession();
session.beginTransaction();
b = reload(b);
b.setName("b2");
session.saveOrUpdate(b);
- session.getTransaction().commit();
+ commitAndResetSession();
+ b = reload(b);
+ assertEquals("b2", b.getName());
}
+ public void testSaveOrUpdateDetached() {
+ session.beginTransaction();
+ Building b = building("b");
+ floor(b, 23);
+ session.saveOrUpdate(b);
+ commitAndResetSession();
+ // let's do saveOrUpdate on a detached entity
+ Building transientB = building("b2");
+ transientB.setBuildingId(b.getBuildingId());
+ session.saveOrUpdate(transientB);
+ commitAndResetSession();
+ b = reload(b);
+ assertEquals("b2", b.getName());
+ }
+
public void testSavingOneToManyChildViaCascade() {
session.beginTransaction();
Building b = building("awesome building");
@@ -837,6 +849,60 @@
}
}
+ public void testUpdateOfAttachedEntity() {
+ session.beginTransaction();
+ Building b = building("b1");
+ session.save(b);
+ commitAndResetSession();
+ b = reload(b);
+ b.setName("other name");
+ session.update(b);
+ commitAndResetSession();
+ b = reload(b);
+ assertEquals("other name", b.getName());
+ }
+
+ // calling update on a detached entity should actually result in a merge
+ public void testUpdateOfDetachedEntity() {
+ session.beginTransaction();
+ Building b = building("b1");
+ session.save(b);
+ commitAndResetSession();
+ Building transientB = building("a different name");
+ transientB.setBuildingId(b.getBuildingId());
+ session.update(transientB);
+ commitAndResetSession();
+ b = (Building) session.get(Building.class, transientB.getBuildingId());
+ assertNotNull(b);
+ assertEquals("a different name", b.getName());
+ }
+
+ public void testDeleteOfAttachedEntity() {
+ session.beginTransaction();
+ Building b = building("b1");
+ session.save(b);
+ commitAndResetSession();
+ b = reload(b);
+ session.delete(b);
+ commitAndResetSession();
+ b = reload(b);
+ assertNull(b);
+ }
+
+ public void testDeleteOfDetachedEntity() {
+ session.beginTransaction();
+ Building b = building("b1");
+ session.save(b);
+ commitAndResetSession();
+ Building detached = new Building();
+ detached.setBuildingId(b.getBuildingId());
+ detached.setName("harold");
+ session.delete(detached);
+ commitAndResetSession();
+ b = reload(b);
+ assertNull(b);
+ }
+
// this is a really good way to shake out synchronization bugs
public void xtestOverAndOver() throws Exception {
final boolean[] go = {true};
Modified: trunk/HibernateExt/shards/src/test/org/hibernate/shards/session/ShardedSessionImplTest.java
===================================================================
--- trunk/HibernateExt/shards/src/test/org/hibernate/shards/session/ShardedSessionImplTest.java 2007-05-02 06:23:27 UTC (rev 11458)
+++ trunk/HibernateExt/shards/src/test/org/hibernate/shards/session/ShardedSessionImplTest.java 2007-05-02 07:38:01 UTC (rev 11459)
@@ -18,15 +18,23 @@
package org.hibernate.shards.session;
-import org.hibernate.shards.defaultmock.ClassMetadataDefaultMock;
-import org.hibernate.shards.defaultmock.InterceptorDefaultMock;
-import org.hibernate.shards.defaultmock.SessionFactoryDefaultMock;
-import org.hibernate.shards.defaultmock.TypeDefaultMock;
+import junit.framework.TestCase;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.metadata.ClassMetadata;
import org.hibernate.shards.Shard;
import org.hibernate.shards.ShardDefaultMock;
import org.hibernate.shards.ShardId;
import org.hibernate.shards.ShardImpl;
import org.hibernate.shards.ShardedSessionFactoryDefaultMock;
+import org.hibernate.shards.defaultmock.ClassMetadataDefaultMock;
+import org.hibernate.shards.defaultmock.InterceptorDefaultMock;
+import org.hibernate.shards.defaultmock.SessionFactoryDefaultMock;
+import org.hibernate.shards.defaultmock.TypeDefaultMock;
import org.hibernate.shards.engine.ShardedSessionFactoryImplementor;
import org.hibernate.shards.strategy.ShardStrategy;
import org.hibernate.shards.strategy.ShardStrategyDefaultMock;
@@ -36,17 +44,9 @@
import org.hibernate.shards.util.Maps;
import org.hibernate.shards.util.Pair;
import org.hibernate.shards.util.Sets;
-
-import junit.framework.TestCase;
-
-import org.hibernate.EntityMode;
-import org.hibernate.HibernateException;
-import org.hibernate.Interceptor;
-import org.hibernate.Session;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.metadata.ClassMetadata;
import org.hibernate.type.Type;
+import java.io.Serializable;
import java.sql.Connection;
import java.util.Collections;
import java.util.List;
@@ -75,35 +75,62 @@
}
public void testApplySaveOrUpdateOperation() {
- final List[] listToReturn = { Lists.newArrayList(new ShardId(0)) };
+ final List<ShardId> shardIdToReturn = Lists.newArrayList(new ShardId(0));
+ final List<Shard> shardListToReturn = Lists.<Shard>newArrayList(new ShardDefaultMock());
+ final Serializable[] idToReturn = {null};
+ final boolean[] saveCalled = {false};
ShardedSessionImpl ssi = new MyShardedSessionImpl() {
@Override
- List<ShardId> determineShardIdsForObjectThatMightAlreadyExist(Object object) {
- return listToReturn[0];
+ public ShardId getShardIdForObject(Object obj) {
+ return shardIdToReturn.get(0);
}
+
+ List<Shard> determineShardsObjectViaResolutionStrategy(Object object) {
+ return shardListToReturn;
+ }
+
+ Serializable extractId(Object object) {
+ return idToReturn[0];
+ }
+
+ public Serializable save(String entityName, Object object)
+ throws HibernateException {
+ saveCalled[0] = true;
+ return null;
+ }
};
final boolean[] saveOrUpdateCalled = { false };
- final boolean[] updateCalled = { false };
+ final boolean[] mergeCalled = { false };
ShardedSessionImpl.SaveOrUpdateOperation op = new ShardedSessionImpl.SaveOrUpdateOperation() {
public void saveOrUpdate(Shard shard, Object object) {
saveOrUpdateCalled[0] = true;
}
- public void update(Shard shard, Object object) {
- updateCalled[0] = true;
+ public void merge(Shard shard, Object object) {
+ mergeCalled[0] = true;
}
+
};
ssi.applySaveOrUpdateOperation(op, null);
assertTrue(saveOrUpdateCalled[0]);
- assertFalse(updateCalled[0]);
+ assertFalse(mergeCalled[0]);
+ shardIdToReturn.set(0, null);
+ saveOrUpdateCalled[0] = false;
+ ssi.applySaveOrUpdateOperation(op, null);
+ assertTrue(saveOrUpdateCalled[0]);
+ assertFalse(mergeCalled[0]);
+ shardIdToReturn.set(0, null);
saveOrUpdateCalled[0] = false;
- listToReturn[0].add(new ShardDefaultMock());
+ shardListToReturn.add(new ShardDefaultMock());
ssi.applySaveOrUpdateOperation(op, null);
assertFalse(saveOrUpdateCalled[0]);
- assertTrue(updateCalled[0]);
+ assertFalse(mergeCalled[0]);
+ assertTrue(saveCalled[0]);
+
+ //TODO(maxr) write test for when we call merge()
}
public void testClose() {
More information about the hibernate-commits
mailing list