Unable to make general purpose query, without Domain entity - spring-data-neo4j

I am new to springbootneo4j. I have difficulties making general purpose queries. I want to be able to make any kind of query and get result without domain entity.
I am making a query like this in repository class:
#Query("MATCH (p:Employee) RETURN ID(p) as id, p.name as name, p.salary as salary ")
that is not working, but the following query is working:
#Query("MATCH (p:Employee) RETURN p ")
My domain entity class is something like this:
#NodeEntity
public class Employee {
#Id
#GeneratedValue
private Long id;
private String name;
private int salary;
#Relationship(type = "IS_BOSSOF", direction = Relationship.UNDIRECTED) Set<Employee> reporties = new HashSet<>();
public Employee() {}
// some more code
}
Create a command is like this:
(laksmi:Employee{name:"Laksmi",salary:200}),(ashwini:Employee{name:"AshwiniV",salary:300}), (harish:Employee{name:"Harish",salary:400}), (jay)-[:IS_BOSSOF]->(mukesh), (xyz)-[:IS_BOSSOF]->(mukesh), (harish)-[:IS_BOSSOF]->(ashwini),

Whenever you are distributing properties you need to use #QueryResult annotation on your class
SDN

Related

How to add multiple wrapper lists into single list

I have created apex class to pull multiple object records into single list. Where objects does not have any relationship (lets say account, contact, lead. Consider account and contact dont have any relationship). I used for loop seperately for each object and saved into wrapperlist. For three objects I have three wrapper list. Now big challenge is I need to add three wrappers(wrapAccount, wrapContact, wrapLead) into single list. So in that list I need all three objects records.
#Auraenabled(cacheable=true)
public static List<sObject> wrapData() {
List<WrapperContact> wrapContact = new List<WrapperContact>();
List<WrapperAccount> wrapAccount = new List<WrapperAccount>();
List<WrapperLead> wrapLead = new List<WrapperLead>();
for(Contact ct : [select id, name from Contact LIMIT 10]){
wrapContact.add(new WrapperContact(ct));
}
for(Account acct : [select id, name from Account LIMIT 10]){
wrapAccount.add(new WrapperAccount(acct));
}
for(Lead ld : [select id, name from Lead LIMIT 10]){
wrapLead.add(new WrapperLead(ld));
}
system.debug('wrapContact'+wrapContact);
system.debug('wrapAccount'+wrapAccount);
system.debug('wrapLead'+wrapLead);
List<SObject> s = new List<SObject>{
new Contact(),
new Account(),
new Lead()
};
public class WrapperAccount{
#Auraenabled
public Account ac{get;set;}
public WrapperAccount(Account acct){
ac=acct;
}
}
public class WrapperContact{
#Auraenabled
public Contact cont{get;set;}
public WrapperContact(Contact ct){
cont=ct;
}
}
public class WrapperLead{
#Auraenabled
public Lead ldd{get;set;}
public WrapperLead(Lead ld){
ldd=ld;
}
}
An example of what I mean:
public class tester {
#Auraenabled(cacheable=true)
public static List<Wrapper> wrapData() {
List<Wrapper> wrap = new List<Wrapper>();
for(Contact ct : [select id, name from Contact LIMIT 10]){
wrap.add(new Wrapper(ct,'contact'));
}
for(Account acct : [select id, name from Account LIMIT 10]){
wrap.add(new Wrapper(acct,'account'));
}
for(Lead ld : [select id, name from Lead LIMIT 10]){
wrap.add(new Wrapper(ld, 'lead'));
}
return wrap;
}
public class Wrapper{
#Auraenabled
public sObject ac{get;set;}
public string objType{get;set;}
public Wrapper(sObject obj, string objtype){
ac=obj;
objType= objtype;
}
}
}
You can then loop through the returned wrapData and display them as you like using a switch and converting them to the correct type. There may be better methods though.

Getting Relationship properties using spring data neo4j node repository

If we have a Company Node like this which is linked to another Node (Location) using OWNS relationship.
#NodeEntity ("Company")
public class Company {
#Id
#Property
private String companyId;
#Property
private String partyId;
#Relationship (type = "OWNS", direction = Relationship . OUTGOING )
private Set<Location> ownedLocations;
}
OWNS relationship
#RelationshipEntity (type = "OWNS")
public class Owns {
#Property
private String ownsProperty;
#StartNode
private Company company;
#EndNode
private Location location;
}
Here is the Repository
#Repository
public interface CompanyRepository extends Neo4jRepository<Company, String> {
#Query ("match (c:Company)-[x:OWNS]-(y) where c.partyId = $0 return c,x,y")
Stream<Company> getCompaniesWithRelationsByPartyId(final String partyId);
}
So when i run this query i am getting only Company and Location entities but no OWNS ownsProperty. How to get relationship properties using above repository?
NOTE: I don't want to use #QueryResult
enter code here
You have to define the Owns relationship entity as the type for the relationship in the Company like this
#Relationship (type = "OWNS", direction = Relationship . OUTGOING )
private Set<Owns> ownedLocations;

Designing Model with foreign key

I am building an ORM by using Unit or Work and Repository using Dapper. I have searched the internet on this problem and no luck.
I have the following tables:
As you can see, Instance has Entity inside. I have 2 approaches:
Approach 1:
public class Entity
{
public int Id {get;set;}
public string Name {get;set;}
}
public class Instance
{
public int Id {get;set;}
public Entity Entity {get;set;}
public string Name {get;set;}
}
How can I get value for Entity with this approach?
Approach 2 (according to this link):
public class Entity
{
public int Id {get;set;}
public string Name {get;set;}
}
public class Instance
{
public int Id {get;set;}
public int EntityId {get;set;}
public string Name {get;set;}
}
Which design is better for use?
You can use QueryMultiple if you want to fetch the data from two different tables and fill it up in two different POCO classes. Following is copied from here:
string sql = "SELECT * FROM Invoice WHERE InvoiceID = #InvoiceID; SELECT * FROM InvoiceItem WHERE InvoiceID = #InvoiceID;";
using (var connection = My.ConnectionFactory())
{
connection.Open();
using (var multi = connection.QueryMultiple(sql, new {InvoiceID = 1}))
{
var invoice = multi.Read<Invoice>().First();
var invoiceItems = multi.Read<InvoiceItem>().ToList();
}
}
Both the models you mentioned in your code can be handled with this approach.
As an alternative approach, you can combine your two POCOs in one or you can use inheritance as well. But, looking at your data model, I do not think this is applicable to this particular case.
Which design is better for use?
Up to you. Whatever suits your project needs keeping down the unnecessary complexities is good for you.

Neo4j RelationshipEntities and cyclic JSON serialization issue with Spring Data Rest

I'm having an issue with serializing #RelationshipEntities to JSON via Spring Data Rest. Whenever I create the #RelationshipEntity, I run into an infinite recursion on serializing the graph to JSON.
Using JSOG to try to render the graph only results in a different, malformed JSON response.
While I can avoid the issue by using #JsonManagedReference, it doesn't solve the problem as I would like to expose the relationship from both nodes.
I've created a simple application that exhibits the issue. It can be found here: https://github.com/cyclomaniac/neo4j-spring-data-rest-cyclic
It implements very basic Team and Player NodeEntities with a single RelationshipEntity, PlayerPosition.
Player:
#NodeEntity
#JsonIdentityInfo(generator= JSOGGenerator.class)
public class Player {
#GraphId
#JsonProperty("id")
private Long id;
private String name;
private String number;
#Relationship(type = "PLAYS_ON")
private PlayerPosition position;
...
Team:
#NodeEntity
#JsonIdentityInfo(generator= JSOGGenerator.class)
public class Team {
#GraphId
#JsonProperty("id")
private Long id;
private String name;
#Relationship(type = "PLAYS_ON", direction = Relationship.INCOMING)
Set<PlayerPosition> teamPlayers;
...
PlayerPosition:
#RelationshipEntity(type="PLAYS_ON")
#JsonIdentityInfo(generator= JSOGGenerator.class)
public class PlayerPosition {
#GraphId
#JsonProperty("id")
private Long id;
private String position;
#StartNode
private Player player;
#EndNode
private Team team;
...
When wired up to a GraphRepository, hitting the /teams endpoint results in the following output with JSOG in place:
{
"_embedded" : {
"teams" : [ {
"#id" : "1",
"name" : "Cubs",
"teamPlayers" : [ {
"#id" : "2",
"position" : "Catcher",
"player" : {
"#id" : "3"
Notice that the JSON ends prematurely. The server throws an exception:
2016-11-04 15:48:03.495 WARN 12287 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write content: Can not start an object,
expecting field name; nested exception is
com.fasterxml.jackson.core.JsonGenerationException:
Can not start an object, expecting field name
My assumption is that I've chosen a poor way to implement the relationship, though it feels fairly straightforward. I'd appreciate any tips on how I can properly expose this relationship, ideally via Spring Data Rest, from both the Team and Player nodes.
Try to annotate with #JsonIgnore or pair: #JsonBackReference and #JsonManagedReference

how to create query in Criteria api

I have a class:
#Entity
public class Resume {
private Long id;
#Embedded
private DesiredPositionAndSalary desiredPositionAndSalary;
}
and class:
#Embeddable
public class DesiredPositionAndSalary {
#ManyToMany
private Set<Specialization> specializations;
}
and class ;)
#Entity
public class Specialization {
private Long id;
}
now i have some Specializations that i need filtered by.
For example i need to select all resume with one of specialization like programmer or manager. Something like
select * from resume r inner join resume_to_specialization rts on r.id = rts.id inner join specialization s on rts.spec_id in(1,2)
how can i write this query in Criteria api? If i miss some major details i can give more.
Ok, i handle it with this:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Resume> cq =cb.createQuery(Resume.class);
Root<Resume> root = cq.from(Resume.class);
cq.select(root);
Set<Specialization> filter = getFilter();
SetJoin<DesiredPositionAndSalary, Specialization> join = root.join(Resume_.desiredPositionAndSalary, JoinType.INNER).join(
DesiredPositionAndSalary_.specializations, JoinType.INNER);
cq.where(cb.and(cq.getRestriction(), join.in(filter)));
cq.distinct(true);/*it is major, or we get duplicate of resume for every
specialization overlap with filter*/
List<Resume> result = em.createQuery(cq).getResultList();
.