In some code I am writing, I build a query dynamically, if I capture theParams
which is a Dictionary <string, object>
and the query
strings and move them to the browser, the query fetches what I need (in the example I am running, it is one record).
In the c# code ... I get nothing (fetched == false
), any ideas?
retVal.AddRange(await session.ExecuteReadAsync(async tx =>
{
var theParams = queryParams.Build();
var cursor = await tx.RunAsync(query, theParams);
var fetched = await cursor.FetchAsync();
while (fetched)
{
... etc
So I have 3 options, if i hardcode the params, <string,object> and <object,object> :
List<string> aParams = [ "c8849ba9-8c87-4a55-9db4-2c2cebbccab1", "a2594625-077e-423b-b3a0-eef12e89824b", "8bc17789-dc82-49f6-94a3-ce2615e41e83", "31d6967b-fcfb-4818-ba8d-8adb0cabacd1", "52a1e6f1-6299-41c1-8fef-d1a044fe064e", "232f8c3d-2ab5-4b28-94e8-d1757063d6f6", "baa97f28-8d06-4fbd-96fa-30089d8fd5ee" ];
var testParams = new
{
theTarget = "54:6b65977c-9dd8-4989-80f4-225b96258645:12750",
theAsset = asset,
var0 = "fe9bb638-c729-4c2b-ba10-6ecba0548aac",
var1 = "b8a0feab-355e-4dc0-9117-837f7a206130",
var2 = "437b6bba-f503-4b40-9710-08d44cf18f2c",
params3 = aParams
};
If I pass the testParams
to the query, I get the expected results; if I pass theParams
, I get 0.
Debugging, testParams
works, queryParams._parameters
which is <string,object>
returns empty, theParams
(an attempt to do <object, object>
) throws an exception
AFAIK, C# has no way of building dynamic objects programmatically, and according to the documentation Neo4J should accept a <string, object>
I have managed to narrow it down to the bug being in a param entry that is an array of strings, in this case $params3 : [ uuid1 ... uuid7 ]
is when the query is not returning anything:
MATCH (R3) WHERE R3.uuid IN $params3 WITH COLLECT(R3) as rOps3
OPTIONAL MATCH (RET)-[:language*0..1]->(V3)
MATCH (:Asset {uuid: $theTarget})<-[partOf]-(RET:Asset { uuid: $theAsset })
WHERE V3 IN rOps3
RETURN DISTINCT RET.uuid AS uuid, RET.publicName AS name
If I execute the query in the browser with the :params
set, it works.
The rest of the query are scalar variables, which seem to work (although some of those alone return nothing - which was expected), the $params3
is the key parameter anyway.
More clues on the issue.
When fixed anonymous object:
List<string> aParams = [ "c8849ba9-8c87-4a55-9db4-2c2cebbccab1", "a2594625-077e-423b-b3a0-eef12e89824b", "8bc17789-dc82-49f6-94a3-ce2615e41e83", "31d6967b-fcfb-4818-ba8d-8adb0cabacd1", "52a1e6f1-6299-41c1-8fef-d1a044fe064e", "232f8c3d-2ab5-4b28-94e8-d1757063d6f6", "baa97f28-8d06-4fbd-96fa-30089d8fd5ee" ];
var testParams = new
{
theTarget = "54:6b65977c-9dd8-4989-80f4-225b96258645:12750",
theAsset = "54:6b65977c-9dd8-4989-80f4-225b96258645:13256",,
var0 = "fe9bb638-c729-4c2b-ba10-6ecba0548aac",
var1 = "b8a0feab-355e-4dc0-9117-837f7a206130",
var2 = "437b6bba-f503-4b40-9710-08d44cf18f2c",
params3 = aParams
};
The type of params3 is List<string>
In a real case when building queries and params dynamically, a parameter is just another object, either a scalar object (e.g. string) which seems to work fine or a list of objects (e.g. list), and the object inside the list could be a scalar type (i assume consistency) or a hierarchy of parameters (e.g. Dictionary<string, object>
).
Not sure about the behaviour when one of the params is nesting params as a Dictionary<string,object>
, but not currently building one.
@dana_canzano any idea who is your dotnet driver guru ? :)
Heylo,
Not a guru, but happy to take a look.
So!
- What version of the driver are you using?
- Can you give a full working code snippet that replicates the issue - I mean - I can attempt to recreate - but I suspect you're 90% there already and we can try to see what's happening faster that way.
All the best
Charlotte
Driver 5.28.1
Not sure how to send you all the code ...
// the method used for testing parameter building from a Dictionary of <string, object>
private readonly Dictionary<string, object> _parameters = new Dictionary<string, object>();
public object BuildTmp()
{
// todo fix error when new drivers are out, temporary method
// ---------------------------------------
List<string> conv(object obj)
{
return ((IEnumerable<object>)obj).Select(o => o?.ToString())
.ToList();
}
var list3 = new List<string>();
if (_parameters.ContainsKey("params3"))
list3 = conv(_parameters["params3"]);
var testParams = new
{
theTarget = _parameters.ContainsKey("theTarget") ? _parameters["theTarget"] as string : "",
theAsset = _parameters.ContainsKey("theAsset") ? _parameters["theAsset"] as string : "",
var0 = _parameters.ContainsKey("var0") ? _parameters["var0"] as string : "",
var1 = _parameters.ContainsKey("var1") ? _parameters["var1"] as string : "",
var2 = _parameters.ContainsKey("var2") ? _parameters["var2"] as string : "",
params3 = list3,
};
return testParams;
}
// the compiled version
List<string> aParams = [ "c8849ba9-8c87-4a55-9db4-2c2cebbccab1", "a2594625-077e-423b-b3a0-eef12e89824b", "8bc17789-dc82-49f6-94a3-ce2615e41e83", "31d6967b-fcfb-4818-ba8d-8adb0cabacd1", "52a1e6f1-6299-41c1-8fef-d1a044fe064e", "232f8c3d-2ab5-4b28-94e8-d1757063d6f6", "baa97f28-8d06-4fbd-96fa-30089d8fd5ee" ];
var testParams = new
{
theTarget = asst.Id,
theAsset = asset,
var0 = "fe9bb638-c729-4c2b-ba10-6ecba0548aac",
var1 = "b8a0feab-355e-4dc0-9117-837f7a206130",
var2 = "437b6bba-f503-4b40-9710-08d44cf18f2c",
params3 = aParams
};
// hardcoded parameter builder
var theParams = queryParams.BuildTmp();
// query using only scalar
query = "MATCH (:Asset {uuid: $theTarget})<-[partOf]-(RET:Asset { uuid:$theAsset })\nRETURN DISTINCT RET.uuid AS uuid, RET.publicName AS name \n";
var Qcursor = await tx.RunAsync(query, theParams);
var Qfetched = await Qcursor.FetchAsync();
var Qtemp = await tx.RunAsync(query, testParams);
var Qbfetched = await Qtemp.FetchAsync();
// query using scalar and list of scalar
query = "MATCH (R3) WHERE R3.uuid IN $params3 WITH COLLECT(R3) as rOps3\nOPTIONAL MATCH (RET)-[:language*0..1]->(V3)\nMATCH (:Asset {uuid: $theTarget})<-[partOf]-(RET:Asset { uuid: $theAsset })\n\nWHERE V3 IN rOps3\nRETURN DISTINCT RET.uuid AS uuid, RET.publicName AS name ";
var cursor = await tx.RunAsync(query, theParams);
var fetched = await cursor.FetchAsync();
var temp = await tx.RunAsync(query, testParams);
var bfetched = await temp.FetchAsync();