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}
Related
Maybe the title itself is enough to express my confusion. In one hand I read a lot that using transaction functions is the recommended way to use the neo4j java driver.
See Neo4j Java Driver
On the other hand, I see examples of codes, such as in Neo4j Java Driver 1.7 API where there is no transaction (or maybe it's implicit), and I like the idea of having a StatementResult and iterating on it.
So what should I do ?
Is there a way of having the iterator of an auto-commit transation in a transaction function ? Should I keep using the execute() function, the session.writeTransaction() function ?
It seems to me that there is a lot of way of running a simple request, but it can't figure why, or if theses methods can be a bit mixed up.
I'm not very happy with writeTransaction if I can only get a String out of it.
There is also the GitHub examples for this driver, especially the ResultRetain with the 'Record' object which is closer of what I'm looking for but without any iterator. It allows data to be extracted with accessers. Another close example is the ResultConsume but still no iterator.
Based on these examples I wrote the following code, it works as expected, with generator and getters.
import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Transaction;
import org.neo4j.driver.v1.TransactionWork;
public class InitializeUser extends Logger{
StatementResult result;
public void getUserForInitialization(){
try ( Session session = driver.session() )
{
result = session.readTransaction( new TransactionWork<StatementResult>()
{
#Override
public StatementResult execute( Transaction tx )
{
return tx.run(
"MATCH (a{initialized:false}) "+
"RETURN a.username as username");
}
} );
}
}
public void readGenerator(){
while (result.hasNext())
{
Record record = result.next();
System.out.println(record.get("username").asString());
}
}
}
I'm not sure if it's worse or better than following the ResultRetain or the ResultConsume example but it has a generator, getters and what I think is transaction functions. I'm still very open to suggestions and explanations.
If someone could explain a bit the mechanic behind TransactionWork(), execute(), and what is the difference between readTransaction(), writeTransaction(), run() and beginTransaction(), I would be delighted.
Neo4j Java Driver
import org.neo4j.driver.v1.AuthTokens;
import org.neo4j.driver.v1.Driver;
import org.neo4j.driver.v1.GraphDatabase;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Transaction;
import org.neo4j.driver.v1.TransactionWork;
import static org.neo4j.driver.v1.Values.parameters;
public class HelloWorldExample implements AutoCloseable
{
private final Driver driver;
public HelloWorldExample( String uri, String user, String password )
{
driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ) );
}
#Override
public void close() throws Exception
{
driver.close();
}
public void printGreeting( final String message )
{
try ( Session session = driver.session() )
{
String greeting = session.writeTransaction( new TransactionWork<String>()
{
#Override
public String execute( Transaction tx )
{
StatementResult result = tx.run( "CREATE (a:Greeting) " +
"SET a.message = $message " +
"RETURN a.message + ', from node ' + id(a)",
parameters( "message", message ) );
return result.single().get( 0 ).asString();
}
} );
System.out.println( greeting );
}
}
public static void main( String... args ) throws Exception
{
try ( HelloWorldExample greeter = new HelloWorldExample( "bolt://localhost:7687", "neo4j", "password" ) )
{
greeter.printGreeting( "hello, world" );
}
}
}
Neo4j Java Driver 1.7 API
import org.neo4j.driver.v1.*;
import static org.neo4j.driver.v1.Values.parameters;
public class SmallExample
{
// Driver objects are thread-safe and are typically made available application-wide.
Driver driver;
public SmallExample(String uri, String user, String password)
{
driver = GraphDatabase.driver(uri, AuthTokens.basic(user, password));
}
private void addPerson(String name)
{
// Sessions are lightweight and disposable connection wrappers.
try (Session session = driver.session())
{
// Wrapping Cypher in an explicit transaction provides atomicity
// and makes handling errors much easier.
try (Transaction tx = session.beginTransaction())
{
tx.run("MERGE (a:Person {name: {x}})", parameters("x", name));
tx.success(); // Mark this write as successful.
}
}
}
private void printPeople(String initial)
{
try (Session session = driver.session())
{
// Auto-commit transactions are a quick and easy way to wrap a read.
StatementResult result = session.run(
"MATCH (a:Person) WHERE a.name STARTS WITH {x} RETURN a.name AS name",
parameters("x", initial));
// Each Cypher execution returns a stream of records.
while (result.hasNext())
{
Record record = result.next();
// Values can be extracted from a record by index or name.
System.out.println(record.get("name").asString());
}
}
}
public void close()
{
// Closing a driver immediately shuts down all open connections.
driver.close();
}
public static void main(String... args)
{
SmallExample example = new SmallExample("bolt://localhost:7687", "neo4j", "password");
example.addPerson("Ada");
example.addPerson("Alice");
example.addPerson("Bob");
example.printPeople("A");
example.close();
}
}
Neo4j Java Driver ResultRetainExample
import java.util.List;
import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.Transaction;
import org.neo4j.driver.v1.TransactionWork;
import static org.neo4j.driver.v1.Values.parameters;
// end::result-retain-import[]
public class ResultRetainExample extends BaseApplication
{
public ResultRetainExample( String uri, String user, String password )
{
super( uri, user, password );
}
// tag::result-retain[]
public int addEmployees( final String companyName )
{
try ( Session session = driver.session() )
{
int employees = 0;
List<Record> persons = session.readTransaction( new TransactionWork<List<Record>>()
{
#Override
public List<Record> execute( Transaction tx )
{
return matchPersonNodes( tx );
}
} );
for ( final Record person : persons )
{
employees += session.writeTransaction( new TransactionWork<Integer>()
{
#Override
public Integer execute( Transaction tx )
{
tx.run( "MATCH (emp:Person {name: $person_name}) " +
"MERGE (com:Company {name: $company_name}) " +
"MERGE (emp)-[:WORKS_FOR]->(com)",
parameters( "person_name", person.get( "name" ).asString(), "company_name",
companyName ) );
return 1;
}
} );
}
return employees;
}
}
private static List<Record> matchPersonNodes( Transaction tx )
{
return tx.run( "MATCH (a:Person) RETURN a.name AS name" ).list();
}
// end::result-retain[]
}
Neo4j Java Driver ResultConsumeExample
import java.util.ArrayList;
import java.util.List;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Transaction;
import org.neo4j.driver.v1.TransactionWork;
// end::result-consume-import[]
public class ResultConsumeExample extends BaseApplication
{
public ResultConsumeExample( String uri, String user, String password )
{
super( uri, user, password );
}
// tag::result-consume[]
public List<String> getPeople()
{
try ( Session session = driver.session() )
{
return session.readTransaction( new TransactionWork<List<String>>()
{
#Override
public List<String> execute( Transaction tx )
{
return matchPersonNodes( tx );
}
} );
}
}
private static List<String> matchPersonNodes( Transaction tx )
{
List<String> names = new ArrayList<>();
StatementResult result = tx.run( "MATCH (a:Person) RETURN a.name ORDER BY a.name" );
while ( result.hasNext() )
{
names.add( result.next().get( 0 ).asString() );
}
return names;
}
// end::result-consume[]
}
I am able to successfully run the Embeddedjava program.but my nodes are not getting reflected when i open the neo4j interface through localhost.For your reference
I made the following changes to my neo4j-server.properties
org.neo4j.server.database.location=C:/neo4j-community-1.9.6/data/graph.db/
org.neo4j.server.webadmin.data.uri=C:/neo4j-community-1.9.6/data/graph.db/
this is the same DB_path that i am using in the code.
Everytime I run the program ,the count on the dashboard increases by 2(i have created 2 nodes in my program).But when i run the query
START root=node(*)
return count(root)
it gives me the answer as 0.
Also,i noticed that the data/keystore file does not get generated when i run the java program.it gets generated only when i start the interface through localhost:7474.Does this have anything to do ?
Java Code
import java.io.File;
import java.io.IOException;
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;
import org.neo4j.kernel.impl.util.FileUtils;
import org.neo4j.kernel.StoreLocker;
public class EmbeddedNeo4j
{
private static final String DB_PATH = "C://neo4j-community-1.9.6//data//graph.db";
public String greeting;
// START SNIPPET: vars
GraphDatabaseService graphDb;
Node firstNode;
Node secondNode;
Relationship relationship;
// END SNIPPET: vars
// START SNIPPET: createReltype
private static enum RelTypes implements RelationshipType
{
KNOWS
}
// END SNIPPET: createReltype
public static void main( final String[] args )
{
EmbeddedNeo4j hello = new EmbeddedNeo4j();
hello.createDb();
hello.removeData();
hello.shutDown();
}
void createDb()
{
// clearDb();
// START SNIPPET: startDb
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
// registerShutdownHook( graphDb );
// END SNIPPET: startDb
// START SNIPPET: transaction
Transaction tx=null;
try
{
tx= graphDb.beginTx();
firstNode = graphDb.createNode();
firstNode.setProperty( "message", "Hello, " );
secondNode = graphDb.createNode();
secondNode.setProperty( "message", "World!" );
relationship = firstNode.createRelationshipTo( secondNode, RelTypes.KNOWS );
relationship.setProperty( "message", "brave Neo4j " );
// END SNIPPET: addData
// START SNIPPET: readData
System.out.print( firstNode.getProperty( "message" ) );
System.out.print( relationship.getProperty( "message" ) );
System.out.print( secondNode.getProperty( "message" ) );
// END SNIPPET: readData
greeting = ( (String) firstNode.getProperty( "message" ) )
+ ( (String) relationship.getProperty( "message" ) )
+ ( (String) secondNode.getProperty( "message" ) );
tx.success();
}
catch(Exception e)
{
tx.failure();
}
finally
{
// Database operations go here
// END SNIPPET: transaction
// START SNIPPET: addData
// START SNIPPET: transaction
tx.finish();
}
// END SNIPPET: transaction
}
private void clearDb()
{
try
{
FileUtils.deleteRecursively( new File(DB_PATH) );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
void removeData()
{
Transaction tx=null;
try
{
tx = graphDb.beginTx() ;
firstNode.getSingleRelationship( RelTypes.KNOWS, Direction.OUTGOING ).delete();
firstNode.delete();
secondNode.delete();
tx.success();
}
catch(Exception e)
{
tx.failure();
}
finally
{
// START SNIPPET: removingData
// let's remove the data
// END SNIPPET: removingData
tx.finish();
}
}
void shutDown()
{
System.out.println();
System.out.println( "Shutting down database ..." );
// START SNIPPET: shutdownServer
graphDb.shutdown();
// END SNIPPET: shutdownServer
}
// START SNIPPET: shutdownHook
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();
}
} );
}
// END SNIPPET: shutdownHook
}
public static void main( final String[] args )
{
EmbeddedNeo4j hello = new EmbeddedNeo4j();
hello.createDb();
hello.removeData();
hello.shutDown();
}
You are creating DB then calling removeData.
If your question is about the webadmin showing you an increase of 2 nodes when the query to count all nodes shows 0, then you should ignore the webadmin node count. It is not truly the number of nodes but sort of the highest node ID in use. The query
START root=node(*)
return count(root)
will correctly show you the number of nodes. This is 0 which is expected since your java program creates nodes and then deletes them.
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.
I'm trying to retrive a list of object with an AsyncCallback call. Everything look fine until I look at the list data in onSuccess procedure. Indeed, I receive a list with the right number of rows, but every rows is the same as the last retrived by SQL statement
this is the EntryPoint client module:
package com.fantaprica.client;
import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.fantaprica.shared.GameDay;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Fantaprica implements EntryPoint {
private final ODBConnectionAsync odbconnectionSvc = GWT
.create(ODBConnection.class);
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public void onModuleLoad() {
odbconnectionSvc
.getGameDayList(new AsyncCallback<List<GameDay>>() {
public void onFailure(Throwable caught) {
}
public void onSuccess(List<GameDay> result) {
System.out.println("#########################################");
System.out.println("OnModuleLoad");
for (int i = 0; i < result.size(); i++) {
System.out.println("index="+i);
System.out.println("result.get(i).getGameDayCompetition()="+result.get(i).getGameDayCompetition());
System.out.println("result.get(i).getGameDayCupFl()"+result.get(i).getGameDayCupFl());
System.out.println("result.get(i).getGameDayId()="+result.get(i).getGameDayId());
System.out.println("result.get(i).getGameDayOrder()="+result.get(i).getGameDayOrder());
System.out.println("result.get(i).getGameDaySeason()="+result.get(i).getGameDaySeason());
}
}
});
}
}
this is the implementation in server side:
package com.fantaprica.server;
import java.text.ParseException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Connection2DB {
public static ResultSet resultset(String p_sql_statement) throws ParseException {
//String db_file_name_prefix = "/home/dario/workspace/fantaprica/src/com/fantaprica/server/database/database";
//String db_file_name_prefix = "/home/dario/workspace/fantaprica/war/database/database";
String db_file_name_prefix = "/home/dario/Workspace/Fantaprica/war/fantaprica/database/database";
Connection con = null;
// connect to the database. This will load the db files and start the
// database if it is not alread running.
// db_file_name_prefix is used to open or create files that hold the
// state
// of the db.
// It can contain directory names relative to the
// current working directory
try {
Class.forName("org.hsqldb.jdbcDriver");
con = DriverManager.getConnection("jdbc:hsqldb:file:"
+ db_file_name_prefix, // filenames prefix
"sa", // user
""); // pass
Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery(p_sql_statement);
System.out.println("query "+p_sql_statement+" eseguita");
statement.close();
con.close();
return rs;
} catch (ClassNotFoundException ex) {
Logger.getLogger(TestConnection.class.getName()).log(Level.SEVERE,
null, ex);
System.out.println("errore "+ex.toString());
return null;
} catch (SQLException ex) {
Logger.getLogger(TestConnection.class.getName()).log(Level.SEVERE,
null, ex);
ex.printStackTrace();
System.out.println("errore "+ex.toString());
return null;
}
}
public static void execstmt(String p_sql_statement) throws ParseException {
String db_file_name_prefix = "/home/dario/Workspace/Fantaprica/war/fantaprica/database/database";
Connection con = null;
// connect to the database. This will load the db files and start the
// database if it is not alread running.
// db_file_name_prefix is used to open or create files that hold the
// state
// of the db.
// It can contain directory names relative to the
// current working directory
try {
Class.forName("org.hsqldb.jdbcDriver");
con = DriverManager.getConnection("jdbc:hsqldb:file:"
+ db_file_name_prefix, // filenames prefix
"sa", // user
""); // pass
Statement statement = con.createStatement();
statement.executeUpdate(p_sql_statement);
System.out.println("statement "+p_sql_statement+" eseguito");
statement.close();
con.close();
} catch (ClassNotFoundException ex) {
Logger.getLogger(TestConnection.class.getName()).log(Level.SEVERE,
null, ex);
System.out.println("errore "+ex.toString());
} catch (SQLException ex) {
Logger.getLogger(TestConnection.class.getName()).log(Level.SEVERE,
null, ex);
ex.printStackTrace();
System.out.println("errore "+ex.toString());
}
}
}
when I run the code, I get these results:
#########################################
ODBConnectionImpl
Start creating the list
scanning resultset
v_game_day_tmp.getGameDayCompetition()=campionato
v_game_day_tmp.getGameDayCupFl()=false
v_game_day_tmp.getGameDayId()=0
v_game_day_tmp.getGameDayOrder()15
v_game_day_tmp.getGameDaySeason()2012/2013
0
index=0
v_game_day_list.get(i).getGameDayCompetition()=campionato
v_game_day_list.get(i).getGameDayCupFl()=false
v_game_day_list.get(i).getGameDayId()=0
v_game_day_list.get(i).getGameDayOrder()=15
v_game_day_list.get(i).getGameDaySeason()=2012/2013
scanning resultset
v_game_day_tmp.getGameDayCompetition()=campionato
v_game_day_tmp.getGameDayCupFl()=false
v_game_day_tmp.getGameDayId()=1
v_game_day_tmp.getGameDayOrder()14
v_game_day_tmp.getGameDaySeason()2012/2013
1
index=1
v_game_day_list.get(i).getGameDayCompetition()=campionato
v_game_day_list.get(i).getGameDayCupFl()=false
v_game_day_list.get(i).getGameDayId()=1
v_game_day_list.get(i).getGameDayOrder()=14
v_game_day_list.get(i).getGameDaySeason()=2012/2013
scanning resultset
v_game_day_tmp.getGameDayCompetition()=campionato
v_game_day_tmp.getGameDayCupFl()=false
v_game_day_tmp.getGameDayId()=2
v_game_day_tmp.getGameDayOrder()13
v_game_day_tmp.getGameDaySeason()2012/2013
2
index=2
v_game_day_list.get(i).getGameDayCompetition()=campionato
v_game_day_list.get(i).getGameDayCupFl()=false
v_game_day_list.get(i).getGameDayId()=2
v_game_day_list.get(i).getGameDayOrder()=13
v_game_day_list.get(i).getGameDaySeason()=2012/2013
scanning resultset
v_game_day_tmp.getGameDayCompetition()=mundialito
v_game_day_tmp.getGameDayCupFl()=false
v_game_day_tmp.getGameDayId()=3
v_game_day_tmp.getGameDayOrder()12
v_game_day_tmp.getGameDaySeason()2012/2013
3
index=3
v_game_day_list.get(i).getGameDayCompetition()=mundialito
v_game_day_list.get(i).getGameDayCupFl()=false
v_game_day_list.get(i).getGameDayId()=3
v_game_day_list.get(i).getGameDayOrder()=12
v_game_day_list.get(i).getGameDaySeason()=2012/2013
list created
#########################################
OnModuleLoad
index=0
result.get(i).getGameDayCompetition()=mundialito
result.get(i).getGameDayCupFl()false
result.get(i).getGameDayId()=3
result.get(i).getGameDayOrder()=12
result.get(i).getGameDaySeason()=2012/2013
index=1
result.get(i).getGameDayCompetition()=mundialito
result.get(i).getGameDayCupFl()false
result.get(i).getGameDayId()=3
result.get(i).getGameDayOrder()=12
result.get(i).getGameDaySeason()=2012/2013
index=2
result.get(i).getGameDayCompetition()=mundialito
result.get(i).getGameDayCupFl()false
result.get(i).getGameDayId()=3
result.get(i).getGameDayOrder()=12
result.get(i).getGameDaySeason()=2012/2013
index=3
result.get(i).getGameDayCompetition()=mundialito
result.get(i).getGameDayCupFl()false
result.get(i).getGameDayId()=3
result.get(i).getGameDayOrder()=12
result.get(i).getGameDaySeason()=2012/2013
As you can see, the list is created correctly in ODBConnectionImpl, and it is composted of 4 different lines.
But when I scan the list returned to AsyncCallback call, I have four equal rows, all equal to the last row from the ResultSet.
Thanks for help and advice,
Dario
I believe the problem is with the code in getGameDayList:
List<GameDay> v_game_day_list = new ArrayList<GameDay>();
GameDay v_game_day_tmp = new GameDay();
String v_sql_statement;
Remove GameDay v_game_day_tmp = new GameDay() from this block of code.
What you are doing is using the same object (v_game_day_tmp) 4 times in the list. As the while loop repopulates v_game_day_tmp and adds to the list, the previous entries in the list are still refering to the same object (v_game_day_tmp) and so will necessarily have the same value.
Do not use 1 temp object.
The object must be recreated with new(), populated and then added to the list.
Simply moving GameDay v_game_day_tmp = new GameDay(); to be the first line of while(rs.next()) should fix your problem.
Regards.
newnoise, SHiv16, I apologize, I made a wrong copy-paste. This is the code of getGameDayList procedure
public List<GameDay> getGameDayList() {
// TODO Auto-generated method stub
List<GameDay> v_game_day_list = new ArrayList<GameDay>();
GameDay v_game_day_tmp = new GameDay();
String v_sql_statement;
try {
v_sql_statement = "SELECT T1.\"game_day_id\",T1.\"game_day_date\",T1.\"game_day_competition\","
+ " T1.\"game_day_season\",T1.\"game_day_cup_fl\",T1.\"game_day_order\""
+ " FROM \"game_days\" T1 ORDER BY T1.\"game_day_order\" DESC";
System.out.println(" ------- ------- -------");
System.out.println("classe ODBConnectionImpl");
System.out.println("getGameDayList");
System.out.println("esecuzione statement " + v_sql_statement);
ResultSet rs = Connection2DB.resultset(v_sql_statement);
System.out.println("query eseguita");
int i = 0;
System.out.println("#########################################");
System.out.println("ODBConnectionImpl");
System.out.println("Start creating the list");
while (rs.next()) {
v_game_day_tmp.getGameDay(rs.getDate("game_day_date"),
rs.getString("game_day_competition"),
rs.getString("game_day_season"),
rs.getBoolean("game_day_cup_fl"),
rs.getInt("game_day_id"), rs.getInt("game_day_order"));
System.out.println("scanning resultset");
System.out.println("v_game_day_tmp.getGameDayCompetition()="+v_game_day_tmp.getGameDayCompetition());
System.out.println("v_game_day_tmp.getGameDayCupFl()="+v_game_day_tmp.getGameDayCupFl());
System.out.println("v_game_day_tmp.getGameDayId()="+v_game_day_tmp.getGameDayId());
System.out.println("v_game_day_tmp.getGameDayOrder()"+v_game_day_tmp.getGameDayOrder());
System.out.println("v_game_day_tmp.getGameDaySeason()"+v_game_day_tmp.getGameDaySeason());
System.out.println(i);
v_game_day_list.add(v_game_day_tmp);
System.out.println("index="+i);
System.out.println("v_game_day_list.get(i).getGameDayCompetition()="+v_game_day_list.get(i).getGameDayCompetition());
System.out.println("v_game_day_list.get(i).getGameDayCupFl()="+v_game_day_list.get(i).getGameDayCupFl());
System.out.println("v_game_day_list.get(i).getGameDayId()="+v_game_day_list.get(i).getGameDayId());
System.out.println("v_game_day_list.get(i).getGameDayOrder()="+v_game_day_list.get(i).getGameDayOrder());
System.out.println("v_game_day_list.get(i).getGameDaySeason()="+v_game_day_list.get(i).getGameDaySeason());
i++;
}
for(i=0;i<v_game_day_list.size();i++)
System.out.println("secondo loop v_game_day_list.get(i).getGameDayId()="+v_game_day_list.get(i).getGameDayId());
System.out.println("list created");
return v_game_day_list;
} catch (SQLException e) {
System.out.println("ODBConnectionImpl SQLException: "
+ e.toString());
return null;
} catch (ParseException e) {
System.out.println("ODBConnectionImpl ParseException: "
+ e.toString());
return null;
}
}
And this is the code of shared class GameDay:
package com.fantaprica.shared;
import java.util.Date;
import java.io.Serializable;
#SuppressWarnings("serial")
public class GameDay implements Serializable {
private int v_game_day_id;
private Date v_game_day_date;
private String v_game_day_competition;
private String v_game_day_season;
private boolean v_game_day_cup_fl;
private int v_game_day_order;
public GameDay() {
// TODO Auto-generated constructor stub
}
// questo metodo viene uitilizzato per l'UPDATE
public void setGameDay(int p_game_day_id,Date p_game_day_date, String p_game_day_competition,
String p_game_day_season, boolean p_game_day_cup_fl) {
v_game_day_id = p_game_day_id;
v_game_day_date = p_game_day_date;
v_game_day_competition = p_game_day_competition;
v_game_day_season = p_game_day_season;
v_game_day_cup_fl = p_game_day_cup_fl;
}
// questo metodo viene utilizzato per l'INSERT
public void setGameDay(Date p_game_day_date, String p_game_day_competition,
String p_game_day_season, boolean p_game_day_cup_fl) {
v_game_day_date = p_game_day_date;
v_game_day_competition = p_game_day_competition;
v_game_day_season = p_game_day_season;
v_game_day_cup_fl = p_game_day_cup_fl;
}
public void getGameDay(Date p_game_day_date, String p_game_day_competition,
String p_game_day_season, boolean p_game_day_cup_fl,
int p_game_day_id, int p_game_day_order) {
v_game_day_date = p_game_day_date;
v_game_day_competition = p_game_day_competition;
v_game_day_season = p_game_day_season;
v_game_day_cup_fl = p_game_day_cup_fl;
v_game_day_id = p_game_day_id;
v_game_day_order = p_game_day_order;
}
public Date getGameDayDate() {
return v_game_day_date;
}
public String getGameDayCompetition() {
return v_game_day_competition;
}
public String getGameDaySeason() {
return v_game_day_season;
}
public boolean getGameDayCupFl() {
return v_game_day_cup_fl;
}
public int getGameDayId() {
return v_game_day_id;
}
public int getGameDayOrder() {
return v_game_day_order;
}
}
I read that the problem could be a "static" implementation of the attribute of thr class, it's not this case, as GameDay class has no static attribute
Dario
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.