Adding a node to Neo4J database using cypher ExecutionEngine - neo4j

Created the database as follows:
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( "D:/TestGraphDatabase" );
cypherEngine = new ExecutionEngine(graphDb, null);
Attempted to add a node in the following manner:
String parentString = "Thing";
String uri = "XXX";
String queryString = "MERGE (owl:{name} {uri: {uri}, name: {name}}) RETURN n";
Map<String, Object> parameters = new HashMap<>();
parameters.put( "name", parentString );
parameters.put( "uri", uri );
resultIterator = (ResourceIterator<Node>) cypherEngine.execute(queryString, parameters).columnAs("n");
result = resultIterator.next();
tx.success();
return result;
This gives me a null pointer exception:
at org.neo4j.cypher.ExecutionEngine.planQuery(ExecutionEngine.scala:85)at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:75)at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:71)
What am I doing wrong?

Needed to pass a StringLogger.DEV_NULL during the ExecutionEngine initialization.

Use the ExecutionEngine in the javacompat package not the other one (which is from Scala).
Then also the results will be easy to handle.
see: http://neo4j.com/docs/stable/tutorials-cypher-java.html
where it says:
Caution:
The classes used here are from the org.neo4j.cypher.javacompat package, not org.neo4j.cypher, see link to the Java API below.

Related

Cannot parse id for appbundles using Design Automation SDK

Here I am again trying to use the Design Automation SDK and I get this error when I try to retrieve bundle aliases, versions or other information that require the id.
I am testing that using one of the existing appbundles available...
public static async Task<dynamic> GetAppBundleVersionsAsync(ForgeService service, Token token, string id)
{
try
{
if (token.ExpiresAt < DateTime.Now)
token = Get2LeggedToken();
AppBundlesApi appBundlesApi = new AppBundlesApi(service);
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("Authorization", "Bearer " + token.AccessToken);
headers.Add("content-type", "application/json");
var aliases = await appBundlesApi.GetAppBundleVersionsAsync(id, null, null, headers);
return aliases;
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error : {0}", ex.Message));
return null;
}
}
Almost thinking to go to my previous RestSharp implementation :)
There are 2 kinds of IDs:
Fully qualified (string in format owner.name+alias)
Unqualified (just name)
You are trying to list versions of your own AppBundle, so you need to use Unqualified. It seems your ID is fully qualified form.
For more info look at API documentation description of endpoint id parameter you are using https://forge.autodesk.com/en/docs/design-automation/v3/reference/http/design-automation-appbundles-id-versions-GET/#uri-parameters

Generic procedure execution method for DAL incl. parameters

I am trying to create a "generic" method in a data access layer that executes a passed stored procedure in Sql Server and also takes a list / array / collection of SqlParameters, to make the usage of a stored procedure call within other parts of the code easier (without requirement to care for connection, command objects etc).
The goal is sth. like this:
int iAffectedRows = dal.RunProcedure("dbo.mySP", parameters);
The parameters should of course be defined previously but without the types. I want them to be created using the AddwithValue() method of SqlParameterCollection class.
It looks like it's impossible because the SqlParameterCollection class can't be instanciated. Look at this discussion.
Anyone knows how to create this?
It's not a good idea to send in a DbParameterCollection (SqlParameterCollection), since it's tightly coupled (which you have discovered) with the ADO.NET infrastructure that you're trying to abstract away. It's better to map your own parameter representation to the collection inside your method.
You can solve it using something like this:
public class DataAccess
{
private ConnectionStringSettings _settings;
public DataAccess(ConnectionStringSettings settings)
{
_settings = settings;
}
public int RunProcedure(string name, dynamic parameters)
{
using (var conn = CreateConnection())
using (var command = CreateCommand(conn, name, parameters))
{
return command.ExecuteNonQuery();
}
}
private DbConnection CreateConnection()
{
var factory = DbProviderFactories.GetFactory(_settings.ProviderName);
var connection = factory.CreateConnection();
connection.ConnectionString = _settings.ConnectionString;
connection.Open();
return connection;
}
private DbCommand CreateCommand(DbConnection conn, string commandText,
object parameters)
{
var cmd = conn.CreateCommand();
cmd.CommandText = commandText;
cmd.CommandType = CommandType.StoredProcedure;
foreach(PropertyInfo parameter in parameters.GetType().GetProperties())
{
var commandParameter = cmd.CreateParameter();
commandParameter.ParameterName = "#" + parameter.Name;
commandParameter.Value = parameter.GetValue(parameters);
cmd.Parameters.Add(commandParameter);
}
return cmd;
}
}
Callable with a syntax like this:
dal.RunProcedure("dbo.mySP", new {
Parameter1 = value1,
Parameter2 = value2
});
You can greatly simplify the code if you only want to support SqlClient.
But instead of rolling this on your own, use a ready made stable library, such as Dapper.
I ended up with the following solution:
SqlParameter[] parameters = {
new SqlParameter("#p1", SqlDbType.Int) { Value = 999},
new SqlParameter("#p2", SqlDbType.Char, 30, "source") { Value = "test"}
};
da.RunProcedure("[dbo].[SP1]", parameters, out rowsAffected);
The RunProcedure accepts IDataParameter[] parameters and forwards this to an command builder method that adds each single of them into the SqlParameters Property of my SqlCommand object:
private static SqlCommand BuildQueryCommand(string storedProcName, IDataParameter[] parameters)
{
SqlCommand command = new SqlCommand( storedProcName, GetDBConnection() );
command.CommandType = CommandType.StoredProcedure;
if (parameters != null)
{
foreach (SqlParameter parameter in parameters)
{
command.Parameters.Add( parameter );
}
}
return command;
}
This works fine and this way I can add each Param with 1 single line of code (that was my destination #1) incl. all Properties of SqlParameter available (use SqlDBType if required, this is up to the user).

How do I use OData $filter results on the server

I have a working OData controller, which supports all the normal get/put etc.
What I want to do is pass a normal odata $filter string from the client, parse and execute the filter on the server and run some code on the resulting IEnumerable.
I've messed around with ODataQueryContext, ODataQueryOptions, FilterQueryOption etc, but not really got anywhere.
Does anyone have any working examples?
Edit: I've added my function skeleton, just need to fill in the blanks
public HttpResponseMessage GetJobs(string filter)
{
*** How to convert the filter into IQueryable<Job> ***
var queryable = ?????
var settings = new ODataQuerySettings();
var jobs = queryOptions.ApplyTo(querable, settings) as IQueryable<Job>;
CsvSerializer csvSerializer = new CsvSerializer();
string csv = csvSerializer.Serialise(jobs);
string fileName = string.Format("{0} Jobs.csv", filter);
return CreateCsvResponseMessage(csv, fileName);
}
I recently had a scenario where I needed this sort of feature as well. This is what I came up with.
private static IQueryable<T> ApplyODataFilter<T>(IQueryable<T> data, string filterString) where T : class
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<T>(typeof(T).Name);
ODataQueryContext context = new ODataQueryContext(builder.GetEdmModel(), typeof(T), new ODataPath());
ODataQueryOptionParser queryOptionParser = new ODataQueryOptionParser(
context.Model,
context.ElementType,
context.NavigationSource,
new Dictionary<string, string> { { "$filter", filterString } });
FilterQueryOption filter = new FilterQueryOption(filterString, context, queryOptionParser);
IQueryable query2 = filter.ApplyTo(data, new ODataQuerySettings());
return query2.Cast<T>();
}
Try using OData code generator to generate client side code. you can following the following blog:
How to use OData Client Code Generator to generate client-side proxy class
The for the filter, the following is an example:
var q2 = TestClientContext.CreateQuery<Type>("Accounts").Where(acct => acct.Birthday > new DateTimeOffset(new DateTime(2013, 10, 1)));
There are some sample code in the codeplex to show how to do query.
Check this:
https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v3/ODataQueryableSample/Program.cs
Update:
There is some sample code in the controller of the sample I gave you.
Write your code as below:
public IQueryable<Order> Get(ODataQueryOptions queryOptions)
{
if (queryOptions.Filter != null)
{
var settings = new ODataQuerySettings();
var filterResult = queryOptions.ApplyTo(OrderList.AsQueryable(), settings) as IQueryable<Order>;
// Use the filter result here.
}
}
Update 2:
You can get the raw string of the filter from ODataQueryOptions.
public IQueryable<Order> Get(ODataQueryOptions queryOptions)
{
string filterString = queryOptions.Filter.RawValue;
// Use the filterString
}
Update 3:
(Note: ODataProperties is an extension method in static class
System.Web.Http.OData.Extensions.HttpRequestMessageExtensions)
public HttpResponseMessage GetJobs(string filter)
{
var context = new ODataQueryContext(Request.ODataProperties().Model, typeof(Job));
var filterQueryOption = new FilterQueryOption(filter, context);
IQueryable<Job> queryable = GetAllJobs();
var settings = new ODataQuerySettings();
var jobs = filterQueryOption.ApplyTo(queryable, settings) as IQueryable<Job>;
CsvSerializer csvSerializer = new CsvSerializer();
string csv = csvSerializer.Serialise(jobs);
string fileName = string.Format("{0} Jobs.csv", filter);
return CreateCsvResponseMessage(csv, fileName);
}

StoredProcedure return Complex Type , Data Service, Entity FrameWork and WCF

I have Entity Framework TaskTracker.edmx
There is StoredProcedure GetEmployees and used Complex type to return the Data
at TaskTrackerDataService.cs
public static void InitializeService(DataServiceConfiguration config)
{
// Grant only the rights needed to support the client application.
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
[WebGet, WebInvoke(ResponseFormat = WebMessageFormat.Xml)]
public IQueryable<TaskTracker_EDM.EmployeeView> GetEmployees()
{
TaskTracker_EDM.TaskTrackerEntities ctx = new TaskTracker_EDM.TaskTrackerEntities();
return ctx.GetEmployees(string.Empty).AsQueryable();
}
at Client Site [Console Application]
var emps = ctxDSvc.Execute<EmployeeView>(new Uri("http://localhost:2402/TaskTrackerDataService.svc/GetEmployees", UriKind.RelativeOrAbsolute));
foreach (EmployeeView e in emps)
{
Console.WriteLine(string.Format("ID: {0} - {1} ", e.EmployeeID, e.Name));
}
foreach is not working, There is no data in emps.
always emps has
+ emps {System.Data.Services.Client.QueryOperationResponse<TaskTrackerConsoleTest.TaskTrackerDataService.EmployeeView>}
System.Collections.Generic.IEnumerable<TaskTrackerConsoleTest.TaskTrackerDataService.EmployeeView> {System.Data.Services.Client.QueryOperationResponse<TaskTrackerConsoleTest.TaskTrackerDataService.EmployeeView>}
I read that OData doesn't support Complex Type.[Did they fix it] or are there another solution.
Some said, use a Xml to Linq kind of approach to get the complex types. [any help]
Any help or advice.
I Serialize the result [ObjectToString] at the Server before send it to the Client application
then Deserialize it.
If there are other ideas, please don't hesitate to tell me.
1- at TaskTracker_WCF1 -> TaskTrackerData.cs
//When StoredProcedure return Complex Type , Then you need to serialise it [Object To String] before send it to Client application
//OData doesn't support Complex Type
[WebGet]
public String GetEmployees_SPreturnComplexType(String nameSearch)
{
TaskTracker_EDM.TaskTrackerEntities ctx = new TaskTracker_EDM.TaskTrackerEntities();
List<TaskTracker_EDM.EmployeeView> hiEmployeeView = (List<TaskTracker_EDM.EmployeeView>)ctx.GetEmployees("Keko88").ToList();
//Serialize object to String
XmlSerializer serializer = new XmlSerializer(hiEmployeeView.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer,hiEmployeeView);
return writer.ToString();
}
}
2- at Console application at program.cs
TaskTrackerDataService.TaskTrackerEntities ctxDSvc =
new TaskTrackerDataService.TaskTrackerEntities(new Uri("http://localhost:2402/TaskTrackerDataService.svc"));
//=======================================
//2-1Call StoredProcedure return Complex Type
String emps = ctxDSvc.Execute<String>(new Uri(ctxDSvc.BaseUri.ToString() +
"/GetEmployees_SPreturnComplexType", UriKind.RelativeOrAbsolute)).Single();
//2-2We need to Deserialize it before use it
var reader = new StringReader(emps);
var serializer = new XmlSerializer(typeof(List<EmployeeView>));
List<EmployeeView> instance = (List<EmployeeView>)serializer.Deserialize(reader);
//=======================================
foreach (EmployeeView e in instance)
{
Console.WriteLine(string.Format("ID: {0} - {1} ", e.EmployeeID, e.Name));
}
Console.WriteLine();
//=======================================

getOrCreate for java-rest-api neo4j fails

I have a simple relationship test that I am trying to run to create a unique node using Rest API (java-rest-binding) https://github.com/neo4j/java-rest-binding but unfortunately I am stuck on something, here are the details: (the non-unique node and relationship works perfectly fine, its with this that it doesn't, most likely I am doing something naive (pardon my lack on knowledge of neo4j).
final UserModel userModel = new UserModel();
final HashMap<String, Object> uModelAttributes = new HashMap<String, Object>(0);
uModelAttributes.put("name", "AnirudhVyas");
userModel.setAttributes(uModelAttributes);
final HashSet<Action> buyHistory = new HashSet<Action>();
final Action buyAction = new Action();
final ProductModel productModel = new ProductModel();
final HashMap<String, Object> attributes = new HashMap<String, Object>(0);
attributes.put("name", "mercedes benz ");
attributes.put("make", "mercedes benz");
attributes.put("model", "sls 550");
attributes.put("year", "2014");
productModel.setAttributes(attributes);
buyAction.setProduct(productModel);
buyHistory.add(buyAction);
userModel.setBuyHistory(buyHistory);
System.out.println("Before");
new UserModelDAO().createCompleteTree(userModel);
System.out.println("Completed >>>
if i use this on the dao:
final RestNode root = api.getOrCreateNode(api.index().forNodes("users", MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "type", "fulltext")), "name", m
.getAttributes().get("name"), m.getAttributes());
api.getOrCreateNode(api.index().forNodes("products", MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "type", "fulltext")), "name", buyAction.getProduct().getAttributes().get("name"), buyAction.getProduct().getAttributes()), RelationshipTypes.BOUGHT);
This basically Fails with:
java.lang.RuntimeException: Error retrieving or creating node for key name and value AnirudhVyas with index users
at org.neo4j.rest.graphdb.ExecutingRestAPI.getOrCreateNode(ExecutingRestAPI.java:448)
at org.neo4j.rest.graphdb.RestAPIFacade.getOrCreateNode(RestAPIFacade.java:223)
at xxxx.xxxx.xxxx.graph.UserModelCreateTasteKeyNeo4JBatchCallback.recordBatch(UserModelCreateTasteKeyNeo4JBatchCallback.java:61)
There are several ways to do it, one of them is using Cypher:
MATCH a
WHERE a.name! = 'nameTofound'
CREATE UNIQUE a-[:Relationship]-c:LABEL
RETURN c
Use it inside a queryEngine.
It works like a charm, please look at the following link for more details:
http://docs.neo4j.org/chunked/milestone/query-create-unique.html
Java code is here:
protected static RestNode createOrGetExistingNode(String key, String valueFor, String Rel, String label){
RestNode node = null;
final QueryResult<Map<String, Object>> result = GraphRestService.queryEngine.query(String.format("MATCH node WHERE node.%s! ='%s' " +
"CREATE UNIQUE node-[:%s]-c:%s RETURN c" , key, valueFor, Rel, label), MapUtil.map("reference", 0));
for (Map<String, Object> column : result) {
node = (RestNode) column.get("c");
}
return node;
}
I solved the problem by not using batch rest callback - When I simply use - getOrCreateXXX( ) for RestAPI it works like a charm - Need to investigate further as to why getOrCreate on BatchCallback#recordBatch( ) will behave differently.

Resources