GenericJpaRepository with ids which are not of type String

Hi all,

Our aggregates have ids which are not of type String (see example below). We would like to use GenericJpaRepository for storing aggregates. The issue we are experiencing is that TypeMismatchException is thrown when GenericJpaRepository wants to load aggregate using EntityManager.

`
@Aggregate(repository=“myAggregateRepository”)
public class MyAggregate {

@EmbeddedId
@AggregateIdentifier
private MyAggregateId myAggregateId;

}

public class MyAggregateId {

private String id;

// factory methods…
}
`

Repository configuraiton looks like this:

`
@Configuration
public class AxonConfig {

// EmbeddedEventStore configuraiton (and some other configuraitons)

@Bean
public GenericJpaRepository myAggregateRepository() {
return new GenericJpaRepository<>(entityManagerProvider, MyAggregate.class,
eventStore(), parameterResolverFactory);
}
}
`

How can we achieve having ids which are not of type String and use GenericJpaRepository?

Thank you!

Hi,

the Repository interface has been going from String to Object and vice versa for quite a while during the Axon 3 design. For certain reasons, Strings were more practical. I think a good “add-on” for the GenericJpaRepository would be to have a function that generates the actual ID type out of a given String, so that JPA can find the correct entity (probably by converting it back to a String again)…

It should be fairly simple to create a specialized implementation of a Repository, by extending the LockingRepository. You can use GenericJpaRepository as an example. The actual code (if you strip the configuration options) is actually very little.

You can also extend GenericJpaRepository and only override the doLoadWithLock method. The other methods actually don’t do anything with the identifier.

Cheers,

Allard

Hello,

Thank You for the answer. This is exactly what we did - we extended the GenericJpaRepository and overridden doLoadWithLock method.

`
class MyJpaRepository<I extends MyAggregateId, T> extends GenericJpaRepository {

private final EntityManagerProvider entityManagerProvider;
private final EventBus eventBus;
private final Class identifierType;

public MyJpaRepository(EntityManagerProvider entityManagerProvider,
Class identifierType,
Class aggregateType,
EventBus eventBus,
ParameterResolverFactory parameterResolverFactory) {
super(entityManagerProvider, aggregateType, eventBus, new PessimisticLockFactory(),
parameterResolverFactory);
this.identifierType= identifierType;
this.entityManagerProvider = entityManagerProvider;
this.eventBus = eventBus;
}

@Override
protected AnnotatedAggregate doLoadWithLock(String aggregateIdentifier, Long expectedVersion) {
I stronglyTypedAggregateIdentifier = MyAggregateId.create(identifierType, aggregateIdentifier);
T aggregateRoot = entityManagerProvider.getEntityManager().find(getAggregateType(),
stronglyTypedAggregateIdentifier);
if (aggregateRoot == null) {
throw new AggregateNotFoundException(aggregateIdentifier,
format(“Aggregate [%s] with identifier [%s] not found”,
getAggregateType().getSimpleName(), aggregateIdentifier));
}
return AnnotatedAggregate.initialize(aggregateRoot, aggregateModel(), eventBus);
}
}
`

And yes, it would be cool to pass the function to the GenericJpaRepository to create the id :slight_smile:

Best,
Milan.

Hi all,

good news coming from Axon regarding this topic - as from version 3.0.5 you are going to be able to pass function (to GenericJpaRepository) which converts your type of id to a string.

Cheers,
Milan.