Механизм @Labels
великолепен, и для многих случаев использования я бы сказал, что это лучшее решение.
Если вы хотите, чтобы другой класс вернулся из вашего хранилища, тогда действительно требуется гораздо больше работы.
Я делаю это в музыкальном проекте.У меня есть Artist
(не абстрактный и полностью пригодный для использования там, где я не знаю, группа это или нет) и Band
и SoloArtist
от Artist с дополнительными метками:
@NodeEntity
public class Artist {}
@NodeEntity
public class Band extends Artist{}
Что я знаю в расширении собственного репозитория, так это:
interface ArtistRepository<T extends Artist> extends Repository<T, Long>, ArtistRepositoryExt {
Optional<T> findOneByName(String name);
// Specifying the relationships is necessary here because the generic queries won't recognize that
// Band has a relationship to country that _should_ be loaded with default depth of 1.
@Query("MATCH (n:Artist) WITH n MATCH p=(n)-[*0..1]-(m) RETURN p ORDER BY n.name")
List<T> findAllOrderedByName();
@Query("MATCH (n:Artist) WHERE id(n) = $id WITH n MATCH p=(n)-[*0..1]-(m) RETURN p")
Optional<T> findById(@Param("id") Long id);
<S extends T> S save(S artist);
}
interface ArtistRepositoryExt {
Band markAsBand(Artist artist);
SoloArtist markAsSoloArtist(Artist artist);
}
class ArtistRepositoryExtImpl implements ArtistRepositoryExt {
private static final String CYPHER_MARK_AS_BAND = String.format(
"MATCH (n) WHERE id(n) = $id\n" +
"OPTIONAL MATCH (n) - [f:BORN_IN] -> (:Country)\n" +
"REMOVE n:%s SET n:%s\n" +
"DELETE f",
SoloArtist.class.getSimpleName(),
Band.class.getSimpleName());
private static final String CYPHER_MARK_AS_SOLO_ARTIST = String.format(
"MATCH (n) WHERE id(n) = $id\n" +
"OPTIONAL MATCH (n) - [f:FOUNDED_IN] -> (:Country)\n" +
"REMOVE n:%s SET n:%s\n" +
"DELETE f",
Band.class.getSimpleName(),
SoloArtist.class.getSimpleName());
private final Session session;
public ArtistRepositoryExtImpl(Session session) {
this.session = session;
}
@Override
public Band markAsBand(Artist artist) {
session.query(CYPHER_MARK_AS_BAND, Map.of("id", artist.getId()));
// Needs to clear the mapping context at this point because this shared session
// will know the node only as class Artist in this transaction otherwise.
session.clear();
return session.load(Band.class, artist.getId());
}
@Override
public SoloArtist markAsSoloArtist(Artist artist) {
session.query(CYPHER_MARK_AS_SOLO_ARTIST, Map.of("id", artist.getId()));
// See above
session.clear();
return session.load(SoloArtist.class, artist.getId());
}
}
Хотя это работает аккуратно, я пойму идею усилий в сценарии с более глубокими вложенными классами.Кроме того, вы должны переопределить производные методы поиска, как я делаю, если вы хотите использовать хранилище полиморфным способом.
Я также храню выделенные хранилища.
Если этот вопрос все еще актуален дляВы, дайте мне знать, если работает для вас тоже.Вы найдете весь проект здесь:
https://github.com/michael-simons/bootiful-music