Settings Relationship Properties in Neo4J OGM - java

I found out about Neo4j OGM yesterday and quickly made a new project to test out how it works. One problem I've come across is setting Relationhip properties as this is crucial for my project. Here's an example:
Room Node:
#NodeEntity
public class Room {
#GraphId
Long id;
#Property(name="name")
String name;
#Relationship(type="CONNECTS")
List<Room> rooms;
public List<Room> getRooms() {
if(rooms == null)
rooms = new ArrayList<Room>();
return rooms;
}
public void setRooms(List<Room> rooms) {
this.rooms = rooms;
}
public Room(String name){
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Room(){
}
public void connectsTo(Room room){
this.getRooms().add(room);
}
}
Connects Node (Relation):
#RelationshipEntity(type="CONNECTS")
public class Connects {
#GraphId
Long id;
#StartNode
Room startMapNode;
#EndNode
Room endMapNode;
#Property(name="length")
int length;
public Connects(Room startMapNode, Room endMapNode){
this.startMapNode = startMapNode;
this.endMapNode = endMapNode;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Room getStartMapNode() {
return startMapNode;
}
public void setStartMapNode(Room startMapNode) {
this.startMapNode = startMapNode;
}
public Room getEndMapNode() {
return endMapNode;
}
public void setEndMapNode(Room endMapNode) {
this.endMapNode = endMapNode;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public Connects(){
}
}
Main method:
public static void main(String[] args) {
SessionFactory sessionFactory = new SessionFactory("at.htl.in110010.domain");
Session session = sessionFactory.openSession("http://localhost:7474");
session.purgeDatabase();
Room roomOne = new Room("TEST_ROOM_ONE");
Room roomTwo = new Room("TEST_ROOM_TWO");
roomOne.connectsTo(roomTwo);
roomTwo.connectsTo(roomOne);
Connects connectRelation = new Connects(roomOne,roomTwo);
connectRelation.setLength(2);
session.save(connectRelation);
}
Now as you can see I've set the length in my main method, but when I check the database under http://localhost:7474 it shows the relation between the nodes but says it has no properties.
Here is the console output: http://pastebin.com/CByfmVcR
Any help in setting the Property would be very appreciated.
Or is there perhaps a different/easier way of mapping objects to the neo4J database ?
Thanks

Using a relationship entity is the right thing to do as you have properties on the relationship. But this also means that your relationship between rooms is represented by Connects.
So, Room should have a reference to Connects rather than to the other Room directly.
e.g.
#Relationship(type="CONNECTS")
List<Connects> rooms;
Here's a test that resembles your domain model:
https://github.com/neo4j/neo4j-ogm/tree/master/src/test/java/org/neo4j/ogm/domain/friendships and
https://github.com/neo4j/neo4j-ogm/blob/master/src/test/java/org/neo4j/ogm/integration/friendships/FriendshipsRelationshipEntityTest.java
I notice you're using neo4j-ogm 1.1.3. Please upgrade to 1.1.4 as it contains important fixes.

Related

SDN4 is not returning nested Entities

Hello Stack overflow,
I have the following Problem:
I have these entity classes:
public class UnknownEntity extends NetworkEntity{
#Id
#GeneratedValue(strategy = UuidStrategy.class)
private String id;
#Override
public void setId(String id) {
this.id = id;
}
#Override
public String getId() {
return id;
}
}
#NodeEntity
public class NetworkEntity {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Id
protected String id;
public List<NetworkInterfaceEntity> getInterfaces() {
return interfaces;
}
public void setInterfaces(List<NetworkInterfaceEntity> interfaces) {
this.interfaces = interfaces;
}
#Relationship(type = "is_composed_of")
protected List<NetworkInterfaceEntity> interfaces ;
}
#NodeEntity
public class NetworkInterfaceEntity {
public String getInterfaceId() {
return interfaceId;
}
public void setInterfaceId(String interfaceId) {
this.interfaceId = interfaceId;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getNetmask() {
return netmask;
}
public void setNetmask(String netmask) {
this.netmask = netmask;
}
public String getMacAddress() {
return macAddress;
}
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public InterfaceState getState() {
return state;
}
public void setState(InterfaceState state) {
this.state = state;
}
public List<NetworkInterfaceEntity> getSubInterfaces() {
return subInterfaces;
}
public void setSubInterfaces(List<NetworkInterfaceEntity> subInterfaces) {
this.subInterfaces = subInterfaces;
}
public long getBytesSent() {
return bytesSent;
}
public void setBytesSent(long bytesSent) {
this.bytesSent = bytesSent;
}
public long getBytesRecived() {
return bytesRecived;
}
public void setBytesRecived(long bytesRecived) {
this.bytesRecived = bytesRecived;
}
#Id
private String interfaceId;
private String ipAddress;
private String netmask;
private String macAddress;
private String name;
private InterfaceState state;
#Relationship(type = "is_composed_of")
private List<NetworkInterfaceEntity> subInterfaces;
private long bytesSent;
private long bytesRecived;
}
When I now try to query the UnknownEntities via a Neo4j Crud Repository with a custom #Query Method, the UnknownEntities wont be nested with the necessary NetworkInterfaceObjects, even tough my query returns these.
public interface UnknownEntityRepository extends CrudRepository<UnknownEntity,String> {
#Query("MATCH (u:UnknownEntity)-[:is_composed_of]->(i:NetworkInterfaceEntity) WHERE i.ipAddress IN {0} WITH u as unknown MATCH p=(unknown)-[r*0..1]-() RETURN collect(unknown),nodes(p),rels(p)")
List<UnknownEntity> searchMachinesByIp(List<String> ipAddresses);
}
In this particular case the NetworkInterfaceEntities do not contain more subInterfaces, so I only want the NetworkInterfaceEntities that belong the the UnknownEntity. But when I use this Query I only get UnknownEntities where the NetworkInterfaceList is null. I even tried different Querys to no avail for example:
"MATCH p=(u:UnknownEntitie)-[:is_composed_of]-(n:NetworkInterfaceEntity) WHERE n.ipAddress in {0} RETURN collect(n),nodes(p),rels(p)".
My Question is, if what I want is even possible with SDN4 Data and if it is, how I can achieve this, Since my alternative is to query the database for every NetworkInterface separately, which I think is really ugly.
Any help would be much appreciated.
please try if returning the full path like this:
public interface UnknownEntityRepository extends CrudRepository<UnknownEntity,String> {
#Query("MATCH (u:UnknownEntity)-[:is_composed_of]->(i:NetworkInterfaceEntity) WHERE i.ipAddress IN {0} WITH u as unknown MATCH p=(unknown)-[r*0..1]-() RETURN p")
List<UnknownEntity> searchMachinesByIp(List<String> ipAddresses);
}
works for your. If not, try naming the objects in question, i.e. RETURN i as subInterfaces works for you.
Are you using Spring Data Neo4j 4 or 5? If you're on 4, consider the upgrade to 5 to be on a supported level.
Please let me know, if this helps.

Accessing 2 models with 1 controller in Java MVC?

Is accessing 2 models with 1 controller in Java MVC alright?
The code looks similar to this:
This is the 1st model
public class People {
private String id, name;
public People(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
I'm still not sure about PeopleList class necessity. This is the 2nd model.
public class PeopleList extends ArrayList<People>{
#Override
public boolean add(People e) {
return super.add(e);
}
#Override
public int size() {
return super.size();
}
}
Here is the controller:
public class PeopleListController {
PeopleList peopleList;
public People findPeopleById(String id) {
People person = new People("", "");
for (People p : peopleList) {
if (p.getId().equals(id)) {
return p;
}
}
return person;
}
}
In the peopleListController, I accessed people using p.getId().
Is it alright? If it is, then it means I don't need to create
peopleController.
Or should I access p.getId() via a new controller
called peopleController?
Or should I just remove the peopleList class
and make an arrayList in this controller? ArrayList peopleList
Thank you for your time.

Spring Hibernate CRUD: ORA-00923: FROM keyword not found where expected

I've been receiving the "ORA-00923: FROM keyword not found where expected" error in my code. I am trying to implement CRUD operations using Spring Hibernate. I've checked for syntax errors as well as quotes in my sql query, but can't seem to detect anything out of the ordinary.
User Class:
package com.spring.model;
import javax.persistence.*;
#Entity
#Table(name="PATIENT_MODEL")
public class User {
private int id;
private String patientFirstName;
private String patientLastName;
private String patientEmail;
private String patientAddress1;
private String patientAddress2;
#Id
#GeneratedValue
#Column(name="PATIENT_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name="PATIENT_FIRST_NAME")
public String getPatientFirstName() {
return patientFirstName;
}
public void setPatientFirstName(String patientFirstName) {
this.patientFirstName = patientFirstName;
}
#Column(name="PATIENT_LAST_NAME")
public String getPatientLastName() {
return patientLastName;
}
public void setPatientLastName(String patientLastName) {
this.patientLastName = patientLastName;
}
#Column(name="PATIENT_EMAIL_ADDRESS")
public String getPatientEmail() {
return patientEmail;
}
public void setPatientEmail(String patientEmail) {
this.patientEmail = patientEmail;
}
#Column(name="PATIENT_ADDRESS_LINE 1")
public String getPatientAddress1() {
return patientAddress1;
}
public void setPatientAddress1(String patientAddress1) {
this.patientAddress1 = patientAddress1;
}
#Column(name="PATIENT_ADDRESS_LINE_2")
public String getPatientAddress2() {
return patientAddress2;
}
public void setPatientAddress2(String patientAddress2) {
this.patientAddress2 = patientAddress2;
}
}
The problem is the #Column(name="PATIENT_ADDRESS_LINE 1"). Could it be the database column is actually named PATIENT_ADDRESS_LINE_1?
If you really need to use column whose name includes one or more spaces, then you need to instruct Hibernate to quote the column name. Also see Oracle documentation.

Cannot bind RemoteObject from BlazeDS

I'm using BlazeDS in Tomcat7 and Flex. I'm trying to use custom classes between the client and server.
In as:
package
{
[Bindable]
[RemoteClass(alias="remoting.Product")]
public class Product
{
public var name:String;
public var id:int;
public var isVisible:Boolean;
}
}
In Java:
package remoting;
public class Product {
public String name;
public int id;
public Boolean isVisible;
public Product(){
name = "Product 0.1";
id = 123;
isVisible = false;
}
public void setName(String _name){
name = _name;
}
public void setId(int _id){
id = _id;
}
public void setVisible(Boolean _isVisible){
isVisible = _isVisible;
}
}
Service part:
public Product echo() {
Product product = new Product();
product.setId(123);
product.setName("My Product");
product.setVisible(true);
return product;
}
I can successfully set the destination of the RemoteObject and call the echo() method. The result event fires up, with the Product object in event.result. However, it does not contain any sensible data. The variables from AS class just get initialized with null, 0 and true values. I'm wondering what's the problem. I tried returning a String with parameters from Product and it works fine, so they get set fine. The problem is in mapping.
I could go another way and implement Externalizable but I don't understand this part from the example:
name = (String)in.readObject();
properties = (Map)in.readObject();
price = in.readFloat();
What if there is a number of strings?
Cheers.
In java class: use private fields and implement getters.
package remoting;
public class Product {
private String name;
private int id;
private Boolean isVisible;
public Product() {
name = "Product 0.1";
id = 123;
isVisible = false;
}
public void setName(String _name){
name = _name;
}
public String getName(){
return name;
}
public void setId(int _id){
id = _id;
}
public int getId(){
return id;
}
public void setIsVisible(Boolean _isVisible){
isVisible = _isVisible;
}
public Boolean getIsVisible() {
return isVisible;
}
}
You could also switch from BlazeDS to GraniteDS: the latter has a powerful transparent externalization mechanism as well as code generation tools that can really save your time (see documentation here).

Linked entities (OneToMany) not shown in Play2 Java form

I'm having trouble with a Play! 2 form in which an object (a member of a neighbourhood association) containing two Lists (of persons in the household and of bank accounts) is edited. Weirdly, the list of persons is properly shown in the form while the textInputs of the bank accounts are empty in the form. The number of bank accounts is correct, though.
I added some debug statements in the edit form template to display the contents of the fields. For the field related to the list of Persons, it shows
BeanList size[2] hasMoreRows[false] list[models.Persoon#1, models.Persoon#2]
while for the list of bank accounts it shows
BeanList deferred
I've cut down the app as much as possible to isolate the issue, and pushed the code to Github (git://github.com/janpascal/ledenadmin.git) on branch debug-form. It seems both lists are created and handled exactly the same, but somehow show up differently. The relation is Cascade-ALL. Just to make sure I've tried adding save() and update() calls when creating the Person or Bankrekening objects, but that doesn't make a difference.
Any help is greatly appreciated!
The form:
#(id: Long, myForm: Form[Lid])
#main("Bewerk lid") {
<h1>Bewerk lid</h1>
#myForm
<br>
#myForm.value()
<br>
#myForm.field("personen").value()
<br>
#myForm.field("rekeningnummers").value()
<br>
#helper.form(action = routes.Leden.saveLid(id)) {
<fieldset>
<legend>Lid #id</legend>
#helper.repeat(myForm("personen"), min = 1) { persoonField =>
#helper.inputText(persoonField("name"), '_label -> "Naam" )
}
#helper.inputText(myForm("address"), '_label -> "Adres")
#helper.repeat(myForm("rekeningnummers"), min = 1) { rekeningField =>
#helper.inputText(rekeningField("rekeningnummer"))
}
</fieldset>
<input type="submit" value="Opslaan">
}
}
My models:
#Entity
public class Lid extends Model {
#GeneratedValue(strategy=GenerationType.AUTO, generator="lid_seq_gen")
#SequenceGenerator(name="lid_seq_gen", sequenceName="LID_SEQ")
#Id
public Long id;
#OneToMany(cascade=CascadeType.ALL, mappedBy="lid")
public List<Persoon> personen;
public String address;
#OneToMany(cascade=CascadeType.ALL, mappedBy="lid")
public List<Bankrekening> rekeningnummers;
public Lid(Long id, String name, String address, String bankaccount) {
this.id = id;
this.personen = new ArrayList<Persoon>();
this.personen.add(new Persoon(this, name));
this.rekeningnummers = new ArrayList<Bankrekening>();
this.rekeningnummers.add(new Bankrekening(this,bankaccount));
this.address = address;
}
public String toString() {
return "Lid "+id+" ("+getFirstName()+")";
}
public String getFirstName() {
if(personen.size()>=1) return personen.get(0).name;
return "";
}
public Bankrekening addRekening(String rekeningnummer) {
Bankrekening rek = new Bankrekening(this, rekeningnummer);
rekeningnummers.add(rek);
return rek;
}
public static void create(Lid lid) {
lid.save();
}
public static void delete(Long id) {
find.ref(id).delete();
}
public static Finder<Long,Lid> find = new Finder<Long, Lid>(
Long.class, Lid.class
);
}
#Entity
public class Persoon extends Model {
#GeneratedValue(strategy=GenerationType.AUTO, generator="persoon_seq_gen")
#SequenceGenerator(name="persoon_seq_gen", sequenceName="PERSOON_SEQ")
#Id
public Long id;
#ManyToOne
public Lid lid;
#Constraints.Required
public String name;
public Persoon(Lid lid, String name) {
this.lid = lid;
this.name = name;
}
public static void create(Persoon p) {
p.save();
}
public static void delete(Long id) {
find.ref(id).delete();
}
public static Finder<Long,Persoon> find = new Finder<Long, Persoon>(
Long.class, Persoon.class
);
}
#Entity
public class Bankrekening extends Model {
#GeneratedValue(strategy=GenerationType.AUTO, generator="bankrek_seq_gen")
#SequenceGenerator(name="bankrek_seq_gen", sequenceName="BANKREKENING_SEQ")
#Id
public Long id;
#ManyToOne
public Lid lid;
#Constraints.Required
public String rekeningnummer;
public Bankrekening(Lid lid, String nummer) {
this.lid = lid;
this.rekeningnummer = nummer;
}
public static void create(Bankrekening bankrekening) {
bankrekening.save();
}
public static void delete(Long id) {
find.ref(id).delete();
}
public static Finder<Long,Bankrekening> find = new Finder<Long, Bankrekening>(
Long.class, Bankrekening.class
);
}
The controller:
public class Leden extends Controller {
public static Result lijst() {
List<Lid> leden = Lid.find.all();
return ok(ledenlijst.render(leden));
}
public static Result bewerkLid(Long id) {
Form<Lid> myForm = form(Lid.class).fill(Lid.find.byId(id));
Lid lid = Lid.find.byId(id);
System.out.println("Editing "+lid.toString());
System.out.print("Bankrekeningen:");
for(Bankrekening rek: lid.rekeningnummers) {
System.out.print(" "+rek.rekeningnummer);
}
System.out.println();
System.out.println("Form information:");
System.out.println(myForm.value());
System.out.println(myForm);
System.out.println(myForm.data());
return ok(editlid.render(id, myForm));
}
public static Result saveLid(Long id) {
Form<Lid> form = form(Lid.class).bindFromRequest();
if(form.hasErrors()) {
return badRequest(editlid.render(id,form));
}
form.get().update(id);
System.out.println("Form information:");
System.out.println(form.value());
System.out.println(form);
System.out.println(form.data());
Lid lid = form.get();
System.out.println("Updating"+lid.toString());
System.out.print(" Bankrekeningen:");
for(Bankrekening rek: lid.rekeningnummers) {
System.out.print(" "+rek.rekeningnummer);
}
return lijst();
}
}
And finally the Global object seeding the database:
public class Global extends GlobalSettings {
#Override
public void onStart(Application app) {
InitialData.insert(app);
}
static class InitialData {
public static void insert(Application app) {
if(Ebean.find(Lid.class).findRowCount() == 0) {
System.out.println("Seeding members");
for(long i=1; i<10; i++) {
Lid lid = new Lid(i, "lid"+i, "Kerkstraat "+i, "Bank account"+i);
//lid.addRekening(new Long(i*5462).toString());
Lid.create(lid);
}
}
}
}
}
This was caused by a dirty Play project somehow, at least cleaning up both the Play installation and the project itself helped.

Categories