Issue Type: Bug Bug
Affects Versions: 3.0.0.Beta2
Assignee: Max Ross
Components: engine
Created: 14/Nov/12 10:36 AM
Description:

This method seems to incorrectly throw an exception if your not using the ShardEncodingIdentifierGenerator to generate ID's for your entities. In my project the Shard ID's are created externally by a NoSql database system and then the data is shard into MySQL for long term storage. All works good when saving the object first time (new) but when trying to update, merge, saveOrUpdate it throws the exception "HibernateException("Can not use virtual sharding with non-shard resolving id gen")" below.

<code>
public ShardId getShardIdForObject(Object obj, List<Shard> shardsToConsider) {
1503 // TODO(maxr)
1504 // Also, wouldn't it be faster to first see if there's just a single shard
1505 // id mapped to the shard?
1506 Shard shard = getShardForObject(obj, shardsToConsider);
1507 if(shard == null) { 1508 return null; 1509 } else if (shard.getShardIds().size() == 1) { 1510 return shard.getShardIds().iterator().next(); 1511 } else {
1512 String className;
1513 if (obj instanceof HibernateProxy) { 1514 className = ((HibernateProxy)obj).getHibernateLazyInitializer().getPersistentClass().getName(); 1515 } else { 1516 className = obj.getClass().getName(); 1517 }
1518 IdentifierGenerator idGenerator = shard.getSessionFactoryImplementor().getIdentifierGenerator(className);
1519 if (idGenerator instanceof ShardEncodingIdentifierGenerator) { 1520 return ((ShardEncodingIdentifierGenerator)idGenerator).extractShardId(getIdentifier(obj)); 1521 } else { 1522 // TODO(tomislav): also use shard resolution strategy if it returns only 1 shard; throw this error in config instead of here 1523 throw new HibernateException("Can not use virtual sharding with non-shard resolving id gen"); 1524 }
1525 }
1526 }
</code>

The fix which I have implemented in my own version of Hibernate Shards. is to change as below. I just return the first shard found in the list because we really don't care which shard the data is on we just need one/any to satisfy our operation or query. In my code I shard on the key and always end up with just one shardId returned from the selectShardIdsFromShardResolutionStrategyData method.

<code>
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; } else if (shard.getShardIds().size() == 1) { return shard.getShardIds().iterator().next(); } else {
String className;
if (obj instanceof HibernateProxy) { className = ((HibernateProxy)obj).getHibernateLazyInitializer().getPersistentClass().getName(); } else { className = obj.getClass().getName(); }
IdentifierGenerator idGenerator = shard.getSessionFactoryImplementor().getIdentifierGenerator(className);
if (idGenerator instanceof ShardEncodingIdentifierGenerator) { return ((ShardEncodingIdentifierGenerator)idGenerator).extractShardId(getIdentifier(obj)); } else {
List<ShardId> shardIds = selectShardIdsFromShardResolutionStrategyData(new
ShardResolutionStrategyDataImpl(obj.getClass(), getIdentifier(obj)));
if (shardIds!=null && shardIds.size() > 0) { return shardIds.get(0); }
throw new HibernateException("Can not resolve shard id using virtual sharding");
}
}
}
</code>

Environment: MySQL, hibernate 3.2, Java, unix
Project: Hibernate Shards
Labels: hibernate query HQL
Priority: Major Major
Reporter: Joe Hopkins
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira