2012-10-23 13 views
19

Ich denke über Federdaten für ein Projekt nach. Ist es möglich, die standardmäßig generierte Speichermethode zu überschreiben? Und wenn ja, wie?Spring Data: Override Speichermethode

+0

Was möchten Sie erreichen? Vielleicht ist AOP ein besserer Ansatz? –

+1

Verwenden Sie keine ID, um festzustellen, ob die betreffende Entität neu ist oder nicht. Die Entity ist unveränderlich, dh, wenn ein Benutzer sie ändert, sollte das System ein neues mit den geänderten Daten erstellen (oder das existierende verwenden, das diesen Daten entspricht. Das einzige Problem, das ich sonst habe, spring data + querydsl sieht für mein Projekt sehr vielversprechend aus. –

+0

Was ist mit der Implementierung von "Persistable"? (Http://static.springsource.org/spring-data/data-commons/docs/1.3.2.RELEASE/api/org/springframework/data/domain/Persistable.html) Wäre das für Sie funktionieren? Auch verwenden Sie Spring Data JPA oder eine andere Back-End-Datenbank? –

Antwort

4

Das hat nicht funktioniert, also habe ich meine benötigte Logik in eine Serviceklasse geschrieben und die Speichermethode save unangetastet gelassen.

6

Ich denke, man SimpleJpaRepository erweitern:

public class **CustomSimpleJpaRepository** extends SimpleJpaRepository { 

@Transactional 
public <S extends T> S save(S entity) { //do what you want instead } 
} 

Dann stellen Sie sicher, das anstelle des Standard SimpleJpaRepository verwendet wird, durch die Erweiterung:

public class CustomJpaRepositoryFactory extends JpaRepositoryFactory { 

    protected <T, ID extends Serializable> JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager entityManager) { 

     Class<?> repositoryInterface = metadata.getRepositoryInterface(); 
     JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType()); 

     SimpleJpaRepository<?, ?> repo = isQueryDslExecutor(repositoryInterface) ? new QueryDslJpaRepository(
      entityInformation, entityManager) : new CustomSimpleJpaRepository(entityInformation, entityManager); 
    repo.setLockMetadataProvider(lockModePostProcessor.getLockMetadataProvider()); 

     return repo; 
    } 
} 

noch nicht fertig, wir müssen auch Ihre eigene Fabrik Bean, um es in der Konfiguration zu verwenden xml:

public class CustomRepositoryFactoryBean <T extends JpaRepository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> { 

protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 
    return new **CustomJpaRepositoryFactory**(entityManager); 
} 

}

die config:

<jpa:repositories base-package="bla.bla.dao" factory-class="xxxx.**CustomRepositoryFactoryBean**"/> 

Hoffe, es hilft.

+0

Die 'isQueryDslExecutor()' Methode scheint privaten Code und die 'LockModePostProcessor'-Klasse nicht vorhanden.Ich habe die' LockModeRepositoryPostProcessor' jedoch mit der gleichen Methode Dies Was du meintest? – coderatchet

1

Verwenden Sie JPA-Ereignis-Listener wie @PrePersist, @PreUpdate. Dies funktioniert, wenn der zugrunde liegende JPA-Anbieter diese Funktionen unterstützt. Dies ist JPA 2-Funktion, so dass der neueste Hibernate, EclipseLink usw. es unterstützen sollte.

+0

Dies funktioniert nicht, da die Logik/der Code, der ausgeführt werden muss, auf die Datenbank zugreifen muss und ich keine Verweise auf die Datenzugriffsebene in meinen Entitätsklassen haben möchte. –

+0

Es gibt mehrere Probleme. Erstens können diese Annotationen ein anbieterspezifisches Verhalten aufweisen. Zweitens sind sie sehr eingeschränkt in dem, was sie tun können; drittens beantwortet dies nicht die OP-Frage, da sie nicht mit den Daten des Frühjahrs zusammenhängt; und schließlich dient keine dieser Anmerkungen dazu, die Speichermethode außer Kraft zu setzen, nicht einmal die persistente Methode von JPA für alles, was es wert ist. Diese Antwort sollte weitgehend abgelehnt werden. –

19

Erstellen Sie einfach Ihre benutzerdefinierte Schnittstelle wie gewohnt und deklarieren Sie dort die Methoden, die Sie mit der gleichen Signatur wie die von CrudRepository (oder JpaRepository, usw.) überlagerte Methode übersteuern möchten. Angenommen, Sie haben eine MyEntity Einheit und ein MyEntityRepository Repository und Sie möchten überschreiben die Standard automatisch generierte save Methode von MyEntityRepository, die eine nur Entitätsinstanz nimmt, dann definieren:

public interface MyEntityRepositoryCustom { 
    <S extends MyEntity> S save(S entity); 
} 

und implementieren diese Methode, wie Sie möchten in Ihrem MyEntityRepositoryImpl, wie üblich:

@Transactional 
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom { 
    public <S extends MyEntity> S save(S entity) { 
    // your implementation 
    } 
} 

Und dann, wie üblich, lassen MyEntityRepositoryMyEntityRepositoryCustom implementieren.

Dadurch ruft Spring Data JPA anstelle der Standardimplementierung die save-Methode Ihres MyEntityRepositoryImpl auf. Zumindest funktioniert das bei mir mit der delete Methode in Spring Data JPA 1.7.2.

+4

Das funktioniert in der Tat. Wichtiges Bit, damit es funktioniert, ist die Namenskonvention beizubehalten. Das heißt, der MyEntityRepositoryImpl-Klassenname muss wie folgt aufgebaut sein: ' Impl' und _not_ wie zum Beispiel' MyEntityRepositoryCustomImpl'. Im letzteren Fall wird es nicht funktionieren. –

+2

Cool, aber wie rufen Sie die Standard-JPARepository.save-Methode von MyEntityRepositoryImpl auf? –

+1

@DanielPinyol Sie lassen Spring den Entity Manager in Ihr 'MyEntityRepositoryImpl' injizieren und rufen dann' persist (Object) 'darauf auf, anstatt auf die standardmäßige' JPAR Repository'-Implementierung. Zu diesem Zweck können Sie '@ PersistenceContext' verwenden. –

3

Um das Überschreiben der standardmäßig generierten Speichermethode zu ermöglichen, müssen Sie die Aggregation der Spring Data Repository-Implementierung in Ihrer eigenen benutzerdefinierten Repository-Implementierung verwenden.

Repository-Schnittstelle:

public interface UserRepository extends CrudRepository<User, String>{ 

} 

Ihre Repository Implementierung:

@Repository("customUserRepository") 
public class CustomUserRepository implements UserRepository { 

    @Autowired 
    @Qualifier("userRepository") // inject Spring implementation here 
    private UserRepository userRepository; 

    public User save(User user) { 
     User user = userRepository.save(entity); 
     // Your custom code goes here 
     return user; 
    } 

    // Delegate other methods here ... 

    @Override 
    public User findOne(String s) { 
     return userRepository.findOne(s); 
    } 
} 

dann Ihre individuelle Implementierung in Ihrem Dienst verwenden:

@Autowired 
@Qualifier("customUserRepository") 
private UserRepository userRepository; 
0

Dies, wenn Sie hilfreich sein könnte ar e werde die ursprüngliche Methode wiederverwenden. Einfach injizieren EntityManager in der implementierenden Klasse.

public interface MyEntityRepositoryCustom { 
    <S extends MyEntity> S save(S entity); 
} 

public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom { 

    // optionally specify unitName, if there are more than one 
    @PersistenceContext(unitName = PRIMARY_ENTITY_MANAGER_FACTORY) 
    private EntityManager entityManager; 

    /** 
    * @see org.springframework.data.jpa.repository.support.SimpleJpaRepository 
    */ 
    @Transactional 
    public <S extends MyEntity> S save(S entity) { 
     // do your logic here 
     JpaEntityInformation<MyEntity, ?> entityInformation = JpaEntityInformationSupport.getMetadata(MyEntity.class, entityManager); 
     if (entityInformation.isNew(entity)) { 
      entityManager.persist(entity); 
      return entity; 
     } else { 
      return entityManager.merge(entity); 
     } 
    } 
}