2012-10-23 8 views
19

Rozważam dane źródłowe dla projektu. Czy można zastąpić domyślnie wygenerowaną metodę zapisu? A jeśli tak, to w jaki sposób?Dane sprężyny: Zastąp metodę zapisu

+0

Co chcesz osiągnąć? Może AOP jest lepszym podejściem? –

+1

Nie używaj id, aby określić, czy dany podmiot jest nowy, czy nie. istota jest niezmienna, jeśli użytkownik ją zmienia, system powinien utworzyć nowy ze zmienionymi danymi (lub użyć istniejącego, który jest równy tym danym) To jedyne obawy, że mam jeszcze dane wiosenne + querydsl wygląda bardzo obiecująco dla mojego projektu. –

+0

Co z implementacją ['Persistable'] (http://static.springsource.org/spring-data/data-commons/docs/1.3.2.RELEASE/api/org/springframework/data/domain/Persistable.html) ? Czy to działa dla Ciebie? Również używasz Spring Data JPA lub jakiejś innej bazy danych back-end? –

Odpowiedz

4

Nie działało to dobrze, więc wprowadziłem wymaganą logikę do klasy usług i pozostawiłem metodę zapisywania nienaruszonych repozytoriów.

6

Chyba przedłużyć SimpleJpaRepository:

public class **CustomSimpleJpaRepository** extends SimpleJpaRepository { 

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

następnie upewnij się, to jest używana zamiast domyślnej SimpleJpaRepository poprzez rozszerzenie:

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; 
    } 
} 

Jeszcze nie zrobione, musimy też mieć własną fabrykę bean użyć w konfiguracji 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); 
} 

}

config:

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

Nadzieję, że to pomaga.

+0

Metoda 'isQueryDslExecutor()' wydaje się być prywatnym kodem, a klasa 'LockModePostProcessor' nie istnieje.Jestem jednak' LockModeRepositoryPostProcessor' z tą samą metodą. to co miałeś na myśli? – coderatchet

1

Służy do korzystania z detektorów zdarzeń JPA, takich jak @PrePersist, @PreUpdate. To zadziała, jeśli bazowy dostawca JPA obsługuje te funkcje. Jest to funkcja JPA 2, więc najnowsza wersja Hibernate, EclipseLink itp. Powinna ją obsługiwać.

+0

To nie działa, ponieważ logika/kod, który musi zostać uruchomiony, musi mieć dostęp do bazy danych i nie chcę mieć odwołań do warstwy dostępu do danych w moich klasach jednostek. –

+0

Istnieje kilka problemów. Po pierwsze, te adnotacje mogą mieć charakterystyczne dla dostawcy zachowania; po drugie, są bardzo ograniczone w tym, co mogą zrobić; po trzecie, nie stanowi to odpowiedzi na pytanie, ponieważ nie ma związku z danymi wiosennymi; i na koniec, żadna z tych adnotacji nie ma zastosowania do nadpisywania metody zapisu, nawet nie istnieje metoda JPA dla wszystkiego, co jest warte. Ta odpowiedź powinna zostać szeroko odrzucona. –

19

Po prostu utwórz niestandardowy interfejs i zadeklaruj tam metody, które chcesz ovverride z tą samą sygnaturą, która jest wystawiona przez CrudRepository (lub JpaRepository, itp.). Załóżmy, że masz MyEntity podmiot i MyEntityRepository repozytorium i chcesz zastąpić domyślny automatycznie wygenerowane save metodę MyEntityRepository który odbywa się tylko wystąpienie encji, a następnie określić:

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

i wdrożenie tej metody, jak chcesz w swojej MyEntityRepositoryImpl, jak zwykle:

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

a potem, jak zwykle, niech MyEntityRepository wdrożyć MyEntityRepositoryCustom.

Wykonując to, Spring Data JPA zadzwoni na metodę save Twojego MyEntityRepositoryImpl zamiast domyślnej implementacji. Przynajmniej to działa dla mnie z metodą delete w Spring Data JPA 1.7.2.

+4

Ten naprawdę działa. Ważne jest, aby zachować konwencję nazewnictwa. Oznacza to, że nazwa klasy MyEntityRepositoryImpl musi być zbudowana jak ' Impl' i _nie_ jako na przykład' MyEntityRepositoryCustomImpl'. Nie zadziała w tym drugim przypadku. –

+2

Fajnie, ale jak wywołać domyślną metodę JPARepository.save z MyEntityRepositoryImpl? –

+1

@DanielPinyol Pozwoliłeś Spring wstrzyknąć menedżer encji w 'MyEntityRepositoryImpl', a następnie wywołać' persist (Object) 'zamiast domyślnej implementacji' JPARepository'. W tym celu możesz użyć '@ PersistenceContext'. –

3

Aby zapewnić zastąpienie domyślnie wygenerowanej metody składowania, należy użyć agregacji implementacji repozytorium danych sprężynowych w ramach własnej implementacji własnego repozytorium.

Repository interfejs:

public interface UserRepository extends CrudRepository<User, String>{ 

} 

Repozytorium realizacja:

@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); 
    } 
} 

Następnie za pomocą implementacji niestandardowych w usłudze:

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

Może to być pomocne, jeśli ar zamierzamy ponownie użyć oryginalnej metody. Wystarczy wprowadzić EntityManager w klasie implementującej.

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); 
     } 
    } 
} 
Powiązane problemy