I have a container object that contains of set of objects that is persisted in Google App Engine using JDO 2.3. I want to remove an object from the set contents. With the following test code, the remove() method returns false, but the change is not persisted, as the following code demonstrates. However, the set cardinality is reduced (this behavior astonishes me). How can I correct this sample to remove the specified object from the set (in this case, object "one")?
I haven't been able to find anything relevant in the JDO documentation. Equality checks and hashing are based on this article.
A dump of the console log with the log level turned up is here (update: this is transactionless version).
A dump of the console log with transactions is here.
Container.java
import java.util.HashSet;
import java.util.Set;
import javax.jdo.annotations.FetchGroup;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
#PersistenceCapable(detachable = "true")
#FetchGroup(name = "withContents", members = { #Persistent(name = "contents") })
public class Container
{
#PrimaryKey
private String id;
#Persistent(dependentElement = "true")
private Set<Containee> contents;
public Set<Containee> getContents()
{
return contents;
}
public Container(String id)
{
super();
this.id = id;
contents = new HashSet<Containee>();
}
}
Containee.java
import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
#PersistenceCapable(detachable = "true")
public class Containee
{
#SuppressWarnings("unused")
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus",
key = "gae.encoded-pk", value = "true")
private String id;
#Persistent
private String friendlyName;
public String getFriendlyName()
{
return friendlyName;
}
public Containee(String friendlyName)
{
this.friendlyName = friendlyName;
}
#Override
public boolean equals(Object other)
{
if (other instanceof Containee)
{
Containee that = (Containee) other;
return this.getFriendlyName().equals(that.getFriendlyName());
}
return false;
}
#Override
public int hashCode()
{
return friendlyName.hashCode();
}
}
Test snippet (run server-side as part of a RemoteService)
...
System.out.println("Fetching...");
Container after = pm.getObjectById(Container.class, "test");
// prints 2
System.out.println("Pre-remove set cardinality "
+ after.getContents().size());
// prints "true"
System.out.println("Post-store containment: "
+ after.getContents().contains(one));
for (Containee e : after.getContents())
{
System.out.println(e.getFriendlyName());
}
System.out.println("Mark");
boolean result = after.getContents().remove(one);
System.out.println("End Mark");
System.out
.println("'after' object class: " + after.getContents().getClass());
// prints "false" (!?!?)
System.out.println("Post-store removal: " + result);
// prints 1 (...?)
System.out.println("Post-remove set cardinality: "
+ after.getContents().size());
...
Edit:
Test snippet with transactions
Container before = new Container("test");
Containee one = new Containee("one");
Containee two = new Containee("two");
Containee three = new Containee("three");
before.getContents().add(one);
before.getContents().add(two);
before.getContents().add(three);
// prints "true"
System.out.println("Pre-store containment: "
+ before.getContents().contains(two));
// prints "true"
System.out.println("Pre-store removal: "
+ before.getContents().remove(two));
PersistenceManager pm = pmf.getPersistenceManager();
try
{
pm.makePersistent(before);
}
finally
{
pm.close();
}
pm = pmf.getPersistenceManager();
pm.getFetchPlan().addGroup("withContents");
Transaction tx = pm.currentTransaction();
try
{
System.out.println("Fetching...");
Container after = pm.getObjectById(Container.class, "test");
// prints 2
System.out.println("Pre-remove set cardinality "
+ after.getContents().size());
// prints "true"
System.out.println("Post-store containment: "
+ after.getContents().contains(one));
for (Containee e : after.getContents())
{
System.out.println(e.getFriendlyName());
}
tx.begin();
System.out.println("Mark");
boolean hrm = after.getContents().remove(one);
System.out.println("End Mark");
tx.commit();
System.out
.println("'after' object class: " + after.getContents().getClass());
// prints "false" (!?!?)
System.out.println("Post-store removal: " + hrm);
// prints 1 (...?)
System.out.println("Post-remove set cardinality: "
+ after.getContents().size());
}
finally
{
System.out.println("Finalizing transaction...");
if (tx.isActive())
{
System.out.println("Rolling back...");
tx.rollback();
}
}
pm.close();
pm = pmf.getPersistenceManager();
pm.getFetchPlan().addGroup("withContents");
try
{
System.out.println("Fetching again...");
Container after = pm.getObjectById(Container.class, "test");
// prints 2
System.out.println("Final set cardinality "
+ after.getContents().size());
}
finally
{
pm.close();
}
Your Relationship is not done correctly.
https://developers.google.com/appengine/docs/java/datastore/jdo/relationships#Owned_One_to_Many_Relationships
Container.java
// ...
#Persistent(mappedBy = "employee", dependentElement = "true")
private Set<Containee> contents;
Containee.java
// ...
#Persistent
private Container container;
After a weekend of head scratching and frustration, I've found a work-around: leverage reference equality instead of value equality when calling Set.remove(). Here's the code (interesting bit starts at the comment "get a reference to the object in the persisted Set"):
Container before = new Container("test");
Containee one = new Containee("one");
Containee two = new Containee("two");
Containee three = new Containee("three");
before.getContents().add(one);
before.getContents().add(two);
before.getContents().add(three);
pm = pmf.getPersistenceManager();
try
{
pm.makePersistent(before);
}
finally
{
pm.close();
}
pm = pmf.getPersistenceManager();
try
{
Container after = pm.getObjectById(Container.class, "test");
// prints 3
System.out.println("Pre-remove set cardinality "
+ after.getContents().size());
// prints "true"
System.out.println("Post-store containment: "
+ after.getContents().contains(one));
//get a reference to the object in the persisted Set
//that is value-equivalent to Containee #1
Containee ref = null;
for (Containee c : after.getContents())
{
if (c.equals(one)) ref = c;
}
if (ref != null)
{
after.getContents().remove(ref);
}
// prints 2
System.out.println("Post-remove set cardinality: "
+ after.getContents().size());
}
finally
{
pm.close();
}
pm = pmf.getPersistenceManager();
try
{
Container after = pm.getObjectById(Container.class, "test");
// prints 2 (as expected)
System.out.println("Final set cardinality "
+ after.getContents().size());
}
finally
{
pm.close();
}
This code doesn't show it, but wrapping the operation with a pessimistic transaction is probably a good plan, to avoid concurrency issues.
The success of this technique leads me to suspect that the DataNucleus framework uses object references instead of equality checks to handle deletions, but I haven't found anything in the documentation that confirms or disproves that hypothesis.
Related
I have a Patients entity class which auto generates an id:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "personId", nullable = false, unique = true)
private Long personId;
public void copy (Patients patient) {
if (patient.getNationality() != null)
this.setNationality(patient.getNationality());
if (patient.getGivenName() != null)
this.setGivenName(patient.getGivenName());
if (patient.getMiddleName() != null)
this.setMiddleName(patient.getMiddleName());
if (patient.getPrefix() != null)
this.setPrefix(patient.getPrefix());
}
/**
* #return PERSONID
*/
public int getPersonId() {
return personId;
}
My addPerson in PersonDaoImpl :
public Patients addPerson(Patients person) {
Patients p = new Patients(person);
try {
em = factory.createEntityManager();
em.getTransaction().begin();
SimpleDateFormat sdfr = new SimpleDateFormat("yyyy-MM-
dd'T'HH:mm:ss.SSS+05:30");
Date date = new Date();
String dateCreated = sdfr.format(date);
p.setDateCreated(dateCreated);
em.persist(p);
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
log.error("Exception caught :: " + e);
p = null;
}
em.close();
return p;
}
My update api in person service class:
#PUT
#Path("/person-manager-resource/updatePersonById")
#Produces("application/json")
#Consumes("application/json")
public Response update(Patients person) {
log.info("Inside UpdatePerson");
log.info(person.getPersonId());
dao = new PersonDaoImpl();
ObjectMapper mapper = new ObjectMapper();
person1 = dao.updatePerson(person);
String result = "";
try {
result = mapper.writeValueAsString(person1);
log.info("Person updated :: " + result);
} catch (JsonProcessingException e) {
log.info("Exception Caught :: " + e);
}
if (person1 != null) {
return Response.
status(Response.Status.OK.getStatusCode()).
entity(result).
build();
} else {
return Response.
status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).
entity(result).
build();
}
}
UpdatePerson:
public Patients updatePerson(Patients updatedPatient) {
Patients dbPatient = new Patients();
TypedQuery<Patients> query = null;
ObjectMapper mapper = new ObjectMapper();
try {
em = factory.createEntityManager();
String identifier = updatedPatient.getPersonIdentifiers().getIdentifier();
String queryStr = "SELECT c FROM Patients c where c.personIdentifiers.identifier = '" + identifier + "'";
query = em.createQuery(queryStr, Patients.class);
dbPatient = query.getSingleResult();
dbPatient.copy(updatedPatient);
em.getTransaction().begin();
em.merge(dbPatient);
em.getTransaction().commit();
} catch (Exception e) {
log.error("Exception caught :: " + e);
em.getTransaction().rollback();
dbPatient = null;
}
em.close();
return dbPatient;
}
I pass a json object through my REST api to create a patient entry:
{
"personId": 5,
"prefix": null,
"givenName": "Pooja roy",
"middleName": null
}
Now this is going fine. I take the same object, which now contains the auto-generated personId, in an api which is supposed to update the object. I pass the json in the Patients entity object. When I print this whole object, the personId is null.
Since it is null and primary key, I can't do a merge. I have to manually update the database object, which is a very lengthy process.
Any ideas why it is coming as null and how I can retrieve it?
I am using postgres.
I think the whole problem is caused by the implementation of the updatePerson method. You should implement the method as follows and it should work as expected, assuming the updatedPatient instance is a persistent entity (meaning it has an ID field set):
public Patients updatePerson(Patients updatedPatient) {
Patients mergedPatient = new Patients();
try {
em = factory.createEntityManager();
em.getTransaction().begin();
mergedPatient = em.merge(updatedPatient);
em.getTransaction().commit();
} catch (Exception e) {
log.error("Exception caught :: " + e);
em.getTransaction().rollback();
}
em.close();
return mergedPatient;
}
Now mergedPatient should contain the synchronized state.
Update:
alternative solution
For whatever reason you cannot use a setter for the ID field. Then the following might solve your problem:
public Patients updatePerson(Patients updatedPatient) {
Patients dbPatient = new Patients();
try {
em = factory.createEntityManager();
String identifier = updatedPatient.getPersonIdentifiers().getIdentifier();
em.getTransaction().begin();
dbPatient = em.find(Patients.class, Long.parseLong(identifier));
dbPatient.copy(updatedPatient);
em.getTransaction().commit();
} catch (Exception e) {
// ..:
dbPatient = null;
}
em.close();
return dbPatient;
}
As the em.find() method is executed inside of a transaction, the object returned is managed, which means any changes to that returned instance will be synchronized with the database when the transaction commits.
PersonId is an auto generated id. So, jpa doesn't allow for me to set a setter for personId. We only have getPersonId() method in the entity class.
So, in updatePerson(Patients person), when I am passing the person object, every setter is called and the object is thus created. Since, personId doesn't have a setter method, it is returned as null in that object.
I have a very curious Error that I cant seem to get my head around.
I need to use a ScheduledExecutorService to pass the Survey Entity I created to be edited and then saved as a new Entity.
public void executeScheduled(Survey eventObject, long interval) {
HashMap<String, String> eventRRules = StringUtils.extractSerialDetails(eventObject.getvCalendarRRule());
long delay = 10000;
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
Runnable runnable = new Runnable() {
private int counter = 1;
private int executions = Integer.parseInt(eventRRules.get("COUNT"));
Survey survey = eventObject;
public void run() {
String uid = eventObject.getUniqueEventId();
logger.info("SurveyController - executeScheduled - Iteration: " + counter);
String serialUid = null;
if (counter == 1) {
serialUid = uid + "-" + counter;
} else {
serialUid = StringUtils.removeLastAndConcatVar(eventObject.getUniqueEventId(), Integer.toString(counter));
}
if (++counter > executions) {
service.shutdown();
}
survey.setUniqueEventId(serialUid);
try {
executeCreateSurvey(survey);
} catch(Exception e) {
logger.debug("SurveyController - executeScheduled - Exception caught: ");
e.printStackTrace();
}
}
};
service.scheduleAtFixedRate(runnable, delay, interval, TimeUnit.MILLISECONDS);
}
When the executeCreateSurvey(survey) Method is run without the ScheduleExecutorService, it works flawlessly.
Yet when it is executed inside the run() Method, I get the "detached entity passed to persist" Error each time the save(survey) Method is run within the executeCreateSurvey() Method....
The executeCreateSurvey() Method where the .save() Method is called:
public ResponseEntity<?> executeCreateSurvey(Survey eventObject) {
MailService mailService = new MailService(applicationProperties);
Participant eventOwner = participantRepositoryImpl.createOrFindParticipant(eventObject.getEventOwner());
eventObject.setEventOwner(eventOwner);
Survey survey = surveyRepositoryImpl.createSurveyOrFindSurvey((Survey) eventObject);
// Saves additional information if small errors (content
// errors,.. )
// occurs
String warnMessage = "";
List<Participant> participants = new ArrayList<Participant>();
for (Participant participantDetached : eventObject.getParticipants()) {
// Check if participant already exists
Participant participant = participantRepositoryImpl.createOrFindParticipant(participantDetached);
participants.add(participant);
// Only create PartSur if not existing (Update case)
if (partSurRepository.findAllByParticipantAndSurvey(participant, survey).isEmpty()) {
PartSur partSur = new PartSur(participant, survey);
partSurRepository.save(partSur);
try {
mailService.sendRatingInvitationEmail(partSur);
surveyRepository.save(survey);
} catch (Exception e) {
// no special exception for "security" reasons
String errorMessage = "error sending mail for participant: " + e.getMessage() + "\n";
warnMessage += errorMessage;
logger.warn("createSurvey() - " + errorMessage);
}
}
}
// Delete all PartSurs and Answers from removed participants
List<PartSur> partSursForParticipantsRemoved = partSurRepository.findAllByParticipantNotIn(participants);
logger.warn("createSurvey() - participants removed: " + partSursForParticipantsRemoved.size());
partSurRepositoryImpl.invalidatePartSurs(partSursForParticipantsRemoved);
return new ResponseEntity<>("Umfrage wurde angelegt. Warnungen: " + warnMessage, HttpStatus.OK);
}
What could the reason be for this?
I have not been able to find this Problem anywhere so far.
I'm trying to create a program for an API to place multiple trades at once, and then get prices for the stocks, and then rebalance every so often. I used a tutorial from online to get some of this code, and made a few tweaks.
However, when I run the code, it often connects and will place an order if I restart IB TWS. But if I go to run the code again it does not work, or show any indication that it will connect. Can anyone help me figure out how to keep the connection going, so that I can run the main.java file, and it will execute multiple trades and then end the connection? Do I need to change the client id number in either the code, or the settings of TWS?
There are three files:
Ordermanagement.java:
package SendMarketOrder;
//import statements//
class OrderManagement extends Thread implements EWrapper{
private EClientSocket client = null; //IB API client Socket Object
private Stock stock = new Stock();
private Order order = new Order();
private int orderId;
private double limitprice;
private String Ticker;
//method to create connection class. It's the constructor
public OrderManagement() throws InterruptedException, ClassNotFoundException, SQLException {
// Create a new EClientSocket object
System.out.println("////////////// Creating a Connection ////////////");
client = new EClientSocket(this); //Creation of a socket to connect
//connect to the TWS Demo
client.eConnect(null,7497,1);
try {
Thread.sleep(3000); //waits 3 seconds for user to accept
while (!(client.isConnected()));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("///////// Connected /////////");
}
public void sendMarketOrder(String cusip, String buyorSell, int shares) throws SQLException, ClassNotFoundException{
//New Order ID
orderId++;
order.m_action = buyorSell;
order.m_orderId = orderId;
order.m_orderType = "MKT";
order.m_totalQuantity = shares;
order.m_account = "DU33xxxxx"; //write own account
order.m_clientId = 1;
//Create a new contract
stock.createContract(cusip);
client.placeOrder(orderId, stock.contract, order);
//Show order in console
SimpleDateFormat time_formatter = new SimpleDateFormat("HH:mm:ss");
String current_time_str = time_formatter.format(System.currentTimeMillis());
System.out.println("////////////////////////////////////////////////\n" +
"#Limit Price: " + order.m_lmtPrice + "///////////////////////////\n" +
"#Client number: " + order.m_clientId + "///////////////////////////\n" +
"#OrderType: " + order.m_orderType + "///////////////////////////\n" +
"#Order Quantity: " + order.m_totalQuantity + "///////////////////////////\n" +
"#Account number: " + order.m_account + "///////////////////////////\n" +
"#Symbol: " + stock.contract.m_secId + "///////////////////////////\n" +
"///////////////////////////////////////"
);
}
Stock.java
public class Stock{
private int StockId; //we can identify the stock
private String Symbol; //Ticker
public Stock() { //default constructor
}
public Stock(int StockId, String Symbol) { //constructor
this.StockId = StockId;
this.Symbol = Symbol;
}
//getter and setters
public int getStockId() {
return StockId;
}
public String getSymbol() {
return Symbol;
}
Contract contract = new Contract ();
public void createContract(String cusip){
contract.m_secId = cusip;
contract.m_secIdType = "CUSIP";
contract.m_exchange = "SMART";
contract.m_secType = "STK";
contract.m_currency = "USD";
}
}
Main.java:
package SendMarketOrder;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws InterruptedException, ClassNotFoundException, SQLException {
OrderManagement order = new OrderManagement();
order.sendMarketOrder("922908363","BUY", 100);
order.sendMarketOrder("92204A504","BUY", 50);
order.sendMarketOrder("92204A702","BUY", 100);
System.exit(0);
}
}
These are my current settings TWS settings if that helps:
Thanks in advance for the help!
I changed a few things around in the code and added comments.
package sendmarketorder;//usually lower case pkg names
public class Main {
//you throw a bunch of exceptions that are never encountered
public static void main(String[] args) {
//since there's a Thread.sleep in this class
//it will block until ready
OrderManagement order = new OrderManagement();
//obviously you need some logic to buy/sell
//you can use command line args here if you want
order.sendMarketOrder("922908363", "BUY", 100);
order.sendMarketOrder("92204A504", "BUY", 50);
order.sendMarketOrder("92204A702", "BUY", 100);
//the socket creates a reader thread so this will stop it.
//if you didn't have this line the non-daemon thread would keep a
//connection to TWS and that's why you couldn't reconnect
//System.exit(0);//use better exit logic
}
}
.
package sendmarketorder;
import com.ib.client.*;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
//doesn't extend thread and if you implement EWrapper you have to implement all methods
//in API 9.72 you can extend DefaultWrapper and just override the methods you need
public class OrderManagement implements EWrapper{
private EClientSocket client = null; //IB API client Socket Object
private int orderId = -1;//use as flag to send orders
//private double limitprice;
//private String Ticker;
//keep track of all working orders
private Map<Integer, Order> workingOrders = new HashMap<>();
//method to create connection class. It's the constructor
public OrderManagement(){
// Create a new EClientSocket object
System.out.println("////////////// Creating a Connection ////////////");
client = new EClientSocket(this); //Creation of a socket to connect
//connect to the TWS Demo
client.eConnect(null, 7497, 123);//starts reader thread
try {
while (orderId < 0){ //not best practice but it works
System.out.println("waiting for orderId");
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("///////// Connected /////////");
}
public void sendMarketOrder(String cusip, String buyorSell, int shares) {
//make new stock and order for each stock
Stock stock = new Stock();
Order order = new Order();
//New Order ID, but get from API as you have to increment on every run for life
orderId++;
order.m_action = buyorSell;
order.m_orderId = orderId;
order.m_orderType = "MKT";
order.m_totalQuantity = shares;
//I don't think you're supposed to use these fields
//order.m_account = "DU33xxxxx"; //write own account
//order.m_clientId = 1;
//Create a new contract
stock.createContract(cusip);
//remember which orders are working
workingOrders.put(orderId, order);
client.placeOrder(orderId, stock.contract, order);
//Show order in console
SimpleDateFormat time_formatter = new SimpleDateFormat("HH:mm:ss");
String current_time_str = time_formatter.format(System.currentTimeMillis());
System.out.println("////////////////////////////////////////////////\n"
+ "#Limit Price: " + order.m_lmtPrice + "///////////////////////////\n"
+ "#Client number: " + order.m_clientId + "///////////////////////////\n"
+ "#OrderType: " + order.m_orderType + "///////////////////////////\n"
+ "#Order Quantity: " + order.m_totalQuantity + "///////////////////////////\n"
+ "#Account number: " + order.m_account + "///////////////////////////\n"
+ "#Symbol: " + stock.contract.m_secId + "///////////////////////////\n"
+ "///////////////////////////////////////"
);
}
//always impl the error callback so you know what's happening
#Override
public void error(int id, int errorCode, String errorMsg) {
System.out.println(id + " " + errorCode + " " + errorMsg);
}
#Override
public void nextValidId(int orderId) {
System.out.println("next order id "+orderId);
this.orderId = orderId;
}
#Override
public void orderStatus(int orderId, String status, int filled, int remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld) {
//so you know it's been filled
System.out.println(EWrapperMsgGenerator.orderStatus(orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld));
//completely filled when remaining == 0, or possible to cancel order from TWS
if (remaining == 0 || status.equals("Cancelled")){
//remove from map, should always be there
if (workingOrders.remove(orderId) == null) System.out.println("not my order!");
}
//if map is empty then exit program as all orders have been filled
if (workingOrders.isEmpty()){
System.out.println("all done");
client.eDisconnect();//will stop reader thread
//now is when you stop the program, but since all
//non-daemon threads have finished, the jvm will close.
//System.exit(0);
}
}
//impl rest of interface...
}
I am working on connecting Neo4j with Java via Eclipse, when I run the code it works and I got the nodes and their relationship between them, now I need to have a cypher query, I tried many ways but they did not work?
I have looked to this, but I had an error.
[EDITED]
Here is my code:
package testtest;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
public class Testnn {
// This is the path of the Neo4J
private static final String Neo4J_DBPath = "/Users/nahla.INTRA/Documents/Neo4j/default.graphdb";
Node first;
Node second;
Relationship relation;
GraphDatabaseService graphDataService;
// List of Relationships first knows second
private static enum RelTypes implements RelationshipType
{
KNOWS
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Testnn hello = new Testnn();
hello.createDatabase();
hello.removeData();
hello.shutDown();
}
void createDatabase ()
{
// GraphDatabaseService
graphDataService = new GraphDatabaseFactory().newEmbeddedDatabase(Neo4J_DBPath);
//Begin Transaction
Transaction transaction = graphDataService.beginTx();
try{
// create nodes and set the properties
first = graphDataService.createNode();
first.setProperty("name", "Tom");
second = graphDataService.createNode();
second.setProperty("name", "Sara");
// Relationship
relation = first.createRelationshipTo(second, RelTypes.KNOWS);
relation.setProperty("relationship-type", "KNOWS");
System.out.println(first.getProperty("name").toString());
System.out.println(relation.getProperty("relationship-type").toString());
System.out.println(second.getProperty("name").toString());
// success Transaction
transaction.success();
}
finally {
//finish the Transaction
transaction.finish();
}
}
void removeData ()
{
Transaction transaction = graphDataService.beginTx();
try
{
// delete
first.getSingleRelationship(RelTypes.KNOWS, Direction.OUTGOING).delete();
System.out.println("Nodes are removed");
// delete nodes
first.delete();
second.delete();
transaction.success();
}
finally
{
// finish the transaction
transaction.finish();
}
}
void shutDown ()
{
// shut down graphDataService
graphDataService.shutdown();
System.out.println("Neo4J database is shutdown");
}
}
and now I have the query part:
try ( Transaction ignored = db.beginTx();
Result result = db.execute( "match (n {name: 'my node'}) return n, n.name" ) )
{
while ( result.hasNext() )
{
Map<String,Object> row = result.next();
for ( Entry<String,Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
}
rows += "\n";
}
}
so,,, first of all how to include the second part of the code to the first one, may be I did not put it in the right place, the second thing : the error is {result can not be resolved}
For the life of me, I cannot understand why I am unable to read a graph I already created in neo4j 1.9.4 community edition. In eclipse, I run the following code:
public class neo4jtest {
private GraphDatabaseService graphDb;
private static final String neo4j_db = "c:/tmp/db/neo4j-new-db";
private UniqueFactory<Node> nodefactory;
private static enum RelTypes implements RelationshipType
{
FRIEND, FOLLOWER
}
public neo4jtest() {
graphDb = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(neo4j_db).
setConfig( GraphDatabaseSettings.node_keys_indexable, "ScreenName,ID" ).
setConfig( GraphDatabaseSettings.relationship_keys_indexable, (RelTypes.FRIEND).name()+","+(RelTypes.FOLLOWER).name()).
setConfig( GraphDatabaseSettings.node_auto_indexing, "true" ).
setConfig( GraphDatabaseSettings.relationship_auto_indexing, "true" ).
newGraphDatabase();
//graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(neo4j_db);
registerShutdownHook( graphDb );
nodefactory = new UniqueFactory.UniqueNodeFactory( graphDb, "users" )
{
#Override
protected void initialize( Node created, Map<String, Object> properties )
{
created.setProperty( "ScreenName", properties.get( "ScreenName" ) );
}
};
}
public void exit() {
graphDb.shutdown();
}
public static void main(String[] args) {
neo4jtest n4 = new neo4jtest();
String u1 = "Moe";
//Node unode = n4.createNeo4jGraph(u1);
n4.exploreNeo4jGraph(u1);
n4.exit();
}
public Node createNeo4jGraph(String uname) {
Node firstNode;
Relationship relationship;
// build a graph
try {
Transaction tx = graphDb.beginTx();
firstNode = nodefactory.getOrCreate("ScreenName", uname);
firstNode.setProperty( "ScreenName", uname );
firstNode.setProperty("ID", 1);
Node followerNode = nodefactory.getOrCreate("ScreenName", "Larry");
followerNode.setProperty("ID", 2);
relationship = firstNode.createRelationshipTo( followerNode, RelTypes.FOLLOWER ); // may not be unique
relationship = followerNode.createRelationshipTo(firstNode, RelTypes.FRIEND);
followerNode = nodefactory.getOrCreate("ScreenName", "Curly");
followerNode.setProperty("ID", 3);
relationship = firstNode.createRelationshipTo( followerNode, RelTypes.FOLLOWER ); // may not be unique
relationship = followerNode.createRelationshipTo(firstNode, RelTypes.FRIEND);
tx.success();
return firstNode;
} catch(Exception ex) {}
return null;
}
private void exploreNeo4jGraph(String scname) {
// use the auto indexer to lookup node with string name
// Get the Node auto index
ReadableIndex<Node> autoNodeIndex = graphDb.index()
.getNodeAutoIndexer()
.getAutoIndex();
Node mainUser = autoNodeIndex.get( "ScreenName", scname ).getSingle();
if (mainUser==null) {
// why not use nodefactory to get it?
System.out.println("Auto indexer did not work");
mainUser = nodefactory.getOrCreate("ScreenName", scname);
}
exploreNeo4jGraph(mainUser);
}
private void exploreNeo4jGraph(Node unode) {
// explore the nodes and edges in the graph
if (unode==null) {
System.err.println("Cannot explore from null node!");
return;
}
long currRels = IteratorUtil.count(GlobalGraphOperations.at(graphDb).getAllRelationships());
long currNodes = IteratorUtil.count(GlobalGraphOperations.at(graphDb).getAllNodes());
System.out.println("Number of nodes in graph is " + currNodes);
System.out.println("Number of edges in graph is " + currRels);
int numberOfFollowers = 0;
String output = unode.getProperty( "ScreenName" ) + "'s friends:\n";
Traverser friendsTraverser = getFriends( unode );
for ( Path friendPath : friendsTraverser )
{
output += "At depth " + friendPath.length() + " <= "
+ friendPath.endNode().getProperty( "ScreenName" ) + "\n";
numberOfFollowers++;
}
output += "Number of friends found: " + numberOfFollowers + "\n";
System.out.println(output);
}
private Traverser getFriends(final Node person )
{
TraversalDescription td = Traversal.description()
.breadthFirst()
.relationships( RelTypes.FRIEND, Direction.INCOMING )
.evaluator( Evaluators.excludeStartPosition() );
return td.traverse( person );
}
private static void registerShutdownHook( final GraphDatabaseService graphDb )
{
// Registers a shutdown hook for the Neo4j instance so that it
// shuts down nicely when the VM exits (even if you "Ctrl-C" the
// running application).
Runtime.getRuntime().addShutdownHook( new Thread()
{
#Override
public void run()
{
graphDb.shutdown();
}
} );
}
}
Basically, I uncomment line
Node unode = n4.createNeo4jGraph(u1);
to create the graph.
Then run it again with that line commented to just explore the graph that was created. When I run it again, it does not report the graph that was created. What am I doing wrong?
Thanks,
D
I'd guess you need to close the transaction. From the javadoc:
finish() (in 1.9)
Commits or marks this transaction for rollback, depending on whether success() or failure() has been previously invoked.