spring data neo4j ignoring #Transient hibernate annotation? - neo4j

In one of my pojo i have used
#RelatedTo(type = "User")
#Transient
private Set<User> users = new HashSet<User>();
which is not mapped with Hibernate, to make hibernate ignore this i have used #Transient, otherwise i am getting Unknown field users but now neo4j is also ignoring the field. It is not storing the relationship. If i remove #Transient neo4j is working fine, but Hibernate is giving execption.
How to resolve this?

Are you using the #NodeEntity annotation with the "partial" argument? This is required for cross-store setups, have a look at the manual: http://static.springsource.org/spring-data/neo4j/docs/2.2.0.RELEASE/reference/htmlsingle/#reference:cross-store

Related

spring data neo4j 6.1.1 Repository Relationship primary_id not allowing to use UUID String where as for Node Primary_id UUID String is working

I have the following relationship entity for neo4j Graph Model using Spring data neo4j 6.1.1 to represent relationship like Person-BookedFor->Movie where i can use UUID string for node repositories (Person, Movie) but not for the following relationship Entity BookedFor.
Note: since the neo4j doc describes this neo4j doc ref
public interface BookedForRepository extends Neo4jRepository<BookedFor, String> {}
#RelationshipProperties
public class BookedFor {
#Id
#GeneratedValue(UUIDStringGenerator.class)
public String rid;
#Property
private Date bookedDate;
}
which throws error as below:
The target class *.entities.BookedFor for the properties of the relationship BookedFor is missing a property for the generated, internal ID (#Id #GeneratedValue Long id) which is needed for safely updating properties
Note: If i use like following, it creates relationship with the internal id of neo4j
public interface BookedForRepository extends Neo4jRepository<BookedFor, Long> {}
#RelationshipProperties
public class BookedFor {
#Id
#GeneratedValue
public Long id;
#Property
private Date bookedDate;
}
but this will create uncertainty on data migration / data mutation as we rely on internal id of neo4j relationship entity. Please correct me if i'm wrong.
spring data neo4j doc ref
Could anyone please help to proceed with this in a better way?
Also, please comment if more clarification / details required.
You cannot access relationship properties directly via repositories.
Those classes are just an encapsulation for properties on relationships and are not meant to represent a "physical" relationship or more a relationship entity.
Repositories are for #Node annotated classes solely.
If you want to access and modify the properties of a relationship, you have to fetch the relationship defining entity.
A relationship on its own is always represented by its start and end node.
The lately introduced required #Id is for internal purposes only.
If you have a special need to persist an id-like property on the relationship, it would be just another property in the #RelationshipProperties annotated class.

how to get the relationship from Collection of relationships between two nodes using springdata Neo4j with GraphRepository

I have two entities like Users and Accounts. User node related to Account node
with any of the 20 relationships. Please find the sample image design attached
i need to search accounts for corresponding users using any of the 20 relationships. i used the cypher query for retriving user details and the accounts.. Relationship between the two entity will be either any one of the 20 relationships . so i can't annotate the #RelationshipEntity type value. Please find the code for example
User.java
public class User
{
private Long id;
String fulltextsearch;
String user_id;
String status;
#Relationship(type = "perm")
List<Acronym> acronym;
.....
...
}
Acronym.java
#JsonIdentityInfo(generator=JSOGGenerator.class)
#RelationshipEntity
public class Acronym {
#GraphId
Long id;
String acronym;
#StartNode
private User user;
#EndNode
private Account account;
....
....
}
Userrepository.java
#RepositoryRestResource(collectionResourceRel = "User", path = "User")
public interface Userrepository extends GraphRepository<User> {
User findByLogin(#Param("login") String login);
#Query("MATCH p=(user:User)-[r*0..1]->(account) WHERE user.login =~('(?i).*'+{Login}+'.*') RETURN p")
Collection<User> findByloginContaining(#Param("login") String login);
}
i tried creating objects for each relationship (ie 20 relationship object.). i'm not sure if that correct way to get the value.
Could anyone please help me to know to fetch the relationships against the account? it always retrives as null.
Thanks in advance.
The OGM/SDN 4 does not support unknown relationship types. The type of relationship must be specified on a #RelationshipEntity.
One way of doing this is as you said, create a #RelationshipEntity per type, but this also means that you must specify 20 such relationships in your User class, because the relationship type differs (even though the start/end nodes are the same). This may not be ideal, and difficult to manage.
If your application primarily works with dynamic relationship types, the OGM may not be a good fit.
NOTE: Mapping custom query results to entities is only supported in OGM 2.x / SDN 4.1. You cannot return a path, just the entities that make up the path such as nodes and rels.

Is there a way to use Specifications in ElasticsearchRepository?

I've implemented the Specification pattern for filtering some of my JpaRepositories. After I have implemented a Specification, I can use it with a JpaRepository like this:
Page<Entity> page = entityJpaRepository.findAll(entitySpecification, pageable)
Is there a feature, or planned feature, for supporting Specifications in ElasticsearchRepository?
I understand your pain however the thing is that Specification interface belongs to the JPA API that currently none of the Elastic Search Spring Data repositories implement and I don't think they will.
If you really want to use them you should rather migrate from ElasticsearchRepository coming from spring-data-elasticsearch into JPA-based repositories.
Did not try to use JPA together with ElasticSearch myself but noticed that some people does it, check out this link:
https://programmertoday.com/spring-boot-elastic-search-with-spring-data-jpa/
I don't know about Specifications, but Spring provides a bean ElasticsearchOperations which has a "search" method which accepts org.springframework.data.elasticsearch.core.query.CriteriaQuery which is similar to standard hibernate Criteria. Try mapping Specification to CriteriaQuery.
#Service
#RequiredArgsConstructor
public class FooService {
private final ElasticsearchOperations elasticsearchTemplate; // autowired bean
public void search() {
Criteria criteria = new Criteria();
criteria.and(new Criteria("foo").is(foo));
criteria.and(new Criteria("bar").in(bars));
CriteriaQuery criteriaQuery = new CriteriaQuery(criteria);
elasticsearchOperations.search(criteriaQuery,
FooElasticEntity.class).stream()
.map(SearchHit::getContent)
.collect(Collectors.toList())
}
}
Also it's worth to note that there is a SearchHitSupport utility class which adds support for Pageable.

Does Spring Data Elasticsearch supports #Id annotation from JPA?

I am getting started to use Spring Data Elasticsearch.
I read:
One of the attributes of the class needs to be an id, either by
annotating it with #Id or using one of the automatically found names
id or documentId.
but when I marked my Project entity field projectId with #Id then elasticsearch still is saying:
No id property found for class com.example.domain.entity.Project!
I figured out that I am using annotation #Id from JPA package: javax.persistence.Id. When I add another #Id annotation #org.springframework.data.annotation.Id for my field then fetching from repository is working!
The issue is that I do not want to use 2 kind of #Id annotation at the same time. Moreover, I would like to use JPA annotation only because of other module is using JPA based repository layer (Spring Data JPA).
Does Spring Data Elasticsearch supports #Id annotation from JPA? It is very important to know because further what about embedded id? Does #EmbeddedId annotation is supported by Spring Data Elasticsearch?
My entity:
#Entity
#Document(indexName = "project_list", type = "external")
public class Project implements Serializable {
#Id
#org.springframework.data.annotation.Id <-- without it Spring Data Elasticsearch is complaining that 'No id property found'
#Column(name = "PROJECT_ID")
private Long projectId;
.... other fields and getters/setters
}
Yes, 1.3.0 does support #Id but you need a getter (maybe a bug?)
ElasticsearchTemplate.getPersistentEntityId takes your entity, tries to find the annotation #Id then returns the value of the id only if there is a getter defined.
However It doesn't seem to support #EmbeddedId: SimpleElasticsearchPersistentProperty.SUPPORTED_ID_PROPERTY_NAMES
I have a similar issue, I am also using JPA and Elastic search both and it resolved after changing
#Column(name = "PROJECT_ID")
private Long projectId;
to
javax.persistence.Id;
the default name of column id
#Column(name = "id")
private Long id;

Spring Data #Query on fields

The #Query on the property retrieves the values only if I retrieve the entity from the DB.
#NodeEntity
public class Team
{
#GraphId
private Long nodeId;
#RelatedTo (type = "PREVIOUSLY_KNOWN_AS")
private Team previouslyKnownAs;
#Query ("START t=node({self}) MATCH t-[:PREVIOUSLY_KNOWN_AS]-other RETURN other")
private Iterable<Team> aliases;
}
The below test works only if I uncomment the line to read it explicitly from the db. Why is it necessary? I see the query being run after the save(t) but the alias field is null if I doesn't read it from DB by uncommenting the line
#Test
public void alias()
{
Team t = new Team();
t.setName("Alpharetta One");
Team prev = new Team();
prev.setName("Previous Name");
teamRepo.save(prev);
t.setPreviouslyKnownAs(prev);
teamRepo.save(t);
//t = teamRepo.findOne(t.getNodeId());//only works if I uncomment
assertNotNull(t.getAliases());
}
Try
t=teamRepo.save(t);
I dont think that the save operation will update the POJO which you give to it, while the returned Object should be a managed enttiy.
The key lies in the reference documentation
The #Query annotation leverages the delegation infrastructure supported by Spring Data Neo4j.It provides dynamic fields which, when accessed, return the values selected by the provided query language expression.
Since it is a dynamic field, the value isnt instanciated but instead fetched from the DB every time the get method is called. To do this, a proxy object has to be used. However there is no way for SDN to change your t Object reference to the proxy object, and thats why its not working, if you are not using the entity returned by save().

Resources