Can any body help me to convert this Cypher Query to neo4jclient?
MATCH (o)-[r]-(post:Post)-[:HAS_MentionedUsers]->(assignee1307989068:User),
WHERE (assignee1307989068.UserName = "mhs")
RETURN post,o,r
UNION
MATCH (o)-[r]-(post:Post)-[:HAS_HashTags]-> (Hashtag1841024507:HashTag)
WHERE (Hashtag1841024507.Value = "myTag")
RETURN post,o,r
Is there any Idea how to create the above cypher query dynamically based on User input which whould be "mhs" and "myTag" in C# and neo4jClient?
Here is what I havetried so far:
The search method will get the search term and tokenize it then BuildPostQueystring method will add each part of the cypher query .
public Object Search(string searchterm)
{
List<string> where = new List<string>();
var tokenizedstring = searchterm.Split(' ');
var querystring = new StringBuilder();
int unionCount = 0;
var q = new CypherFluentQuery(_graphClient) as ICypherFluentQuery;
foreach (var t in tokenizedstring)
{
_commandService.BuildPostQueystring(t, ref querystring, ref where);
if (querystring[querystring.Length - 1] == ',')
querystring = querystring.Remove(querystring.Length - 1, 1);
if (unionCount > 0)
q = q.Union();
q = q.Match(querystring.ToString());
unionCount++;
int i = 1;
if (where.Count > 0)
q = q.Where(where[0]);
while (i < where.Count)
{
q = q.OrWhere(where[i]);
i++;
}
q = q.Return((post, nodes) => new { Post = post.As<Node<string>>(), Nodes = nodes.As<Node<string>>() })
.OrderBy("post.creationDate");
where.Clear();
querystring.Clear();
}
//var rq = q.Return((post, o) => new {Person = post.As<Node<string>>(), Dog = o.As<Node<string>>()})
// .OrderBy("post.creationDate");
var x = (q as CypherFluentQuery<dynamic>).Results;
return x.ToList();
}
The other method that add the query part is as fallow :
public void BuildPostQueystring(string token, ref StringBuilder sb, ref List<string> whereConditions)
{
string querystring = "(nodes)-[r]-(post:Post)-[:HAS_{0}]->({1}:{2})";
string wherestring = "({0}.{1} = \"{2}\")";
if (token.StartsWith("#"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash*-1;
string paramName = "Hashtag" + hash;
var str = string.Format(querystring, "HashTags", paramName, "HashTag");
var tvalue = token.Replace("#", "");
//query = query.AndWhere((HashTag hashTag) => hashTag.Value == tvalue);
sb.Append(str);
whereConditions.Add(string.Format(wherestring, paramName, "Value", tvalue));
}
else if (token.StartsWith("+"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "team" + hash;
var str = string.Format(querystring, paramName, "MentionedTeam","Team");
sb.Append(str);
var tvalue = token.Replace("+", "");
whereConditions.Add(string.Format(wherestring,paramName, "Name", tvalue));
}
else if (token.StartsWith("#"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "assignee" + hash;
var str = string.Format(querystring, "MentionedUsers", paramName, "User");
sb.Append(str);
var tvalue = token.Replace("#", "");
whereConditions.Add(string.Format(wherestring, paramName,"UserName", tvalue));
}
else if (token.StartsWith("by"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "author" + hash;
var str = string.Format(querystring, "Author", paramName, "User");
sb.Append(str);
var tvalue = token.Replace("by:", "");
whereConditions.Add(string.Format(wherestring, paramName, "UserName", tvalue));
}
else if (token.Contains("\\"))
{
foreach (var dt in GetLocalDateTokens(_dateTimeTokens))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "dueDate" + hash;
if (token.ToLower() == dt.Text.ToLower())
{
var neodate = new NeoDateTime();
neodate.Year = dt.GetDate.Year;
neodate.Month = dt.GetDate.Month;
neodate.Day = dt.GetDate.Day;
neodate.TimeStamp = long.Parse(dt.GetDate.ToString("HHmmss"));
neodate.DateStamp = long.Parse(dt.GetDate.ToString("yyyyMMdd"));
neodate.DateTimeStamp = long.Parse(dt.GetDate.ToString("yyyyMMddHHmmss"));
var str = string.Format(querystring, "DueDates", paramName, "NeoDateTim");
sb.Append(str);
var tvalue = token.Replace("by:", "");
whereConditions.Add(string.Format(wherestring, "DateStamp", paramName, tvalue));
}
}
}
else
{
//MATCH (n)
//WHERE n.name =~ 'Tob.*'
//RETURN n
var wherestr = "({0}.{1} =~ '{2}.*')";
//string wherestring = "({0}.{1} = \"{2}\")";
//string querystring = "(post:Post)-[:HAS_{0}]->({1}:{2})";
string paramName = "post" + token + GetHashCode();
string qs = "(post:Post)";
var str = string.Format(qs, paramName);
sb.Append(str);
whereConditions.Add(string.Format(wherestr, "post", "Text", token));
}
if(sb.Length>0)
sb.Append(",");
}
My first problem is how to get result as the q does not have the result method and I cant cast it to an anonymous type?!
OK, firstly, the reason q doesn't have a Results method is because up until you add a Return call you only have an ICypherFluentQuery, so if you have:
var query = client.Cypher.Match("(n:Post)");
query will be of type ICypherFluentQuery which doesn't have a Results method, once you add a Return statement:
var query = client.Cypher.Match("(n:Post)").Return(n => n.As<Post>());
you'll find the query is now: ICypherFluentQuery<Post>. So, before you add your .Return statement, you will need to assign to another variable:
var query = client.Cypher.Match("(n:Post)");
var retQuery = query.Return(n => n.As<Post>());
var results = retQuery.Results;
Second part, the actual query.
It's not entirely clear what you're trying to do with your code, you have a lot of it, but the code for your query (in my view) should look something like this:
private void GetResults(string username, string tagValue)
{
var query = Client.Cypher
.Match("(o)-[r]-(post:Post)-[:HAS_MentionedUsers]->(assignee:User)")
.Where((User assignee) => assignee.UserName == username)
.Return((post, o, r) => new {Post = post.As<Post>(), O = o.As<object>(), R = r.As<RelationshipInstance<object>>()})
.Union()
.Match("(o)-[r]-(post:Post)-[:HAS_MentionedUsers]->(hashTag:HashTag)")
.Where((HashTag hashTag) => hashTag.Value == tagValue)
.Return((post, o, r) => new {Post = post.As<Post>(), O = o.As<object>(), R = r.As<RelationshipInstance<object>>()});
var res = query.Results.ToList();
}
PS: I have no idea what type o is, so I have used object as a placeholder
If for some reason you need to use those names assignee1307989068 etc as you're building up an epic query then the where would become something like:
/* MATCH */
.Where("assignee123.Value == {assignee123Param}")
.WithParam("assignee123", username)
/* RETURN */
If you can, I would go with the first version as it's type safe and easier to understand.
Related
In the below C# code, I am doing 2 iterations over data and trying to create a filter that looks like this,
(Name1 = 'd1' AND Name2 = 'd1') OR (Name1 = 'd3' AND Name2 = 'd3') OR (Name1 != 'd1' AND Name1 != 'd3')
For the below sets of data:
var data = new List<(string, string)>
{
("d1", "d2"), ("d3", "d4"),
};
Here is code:
foreach(var entity in data)
{
filter += $"(Name1 = '{entity.Item1}' AND Name2 = '{entity.Item1}') OR ";
}
filter = filter + "(";
foreach (var entity in data)
{
filter += $"Name1 != '{entity.Item1}' AND ";
}
//remove last "AND"
var final = filter.Substring(0, filter.LastIndexOf("AND")).TrimEnd() + ")";
How I can improve this code and get rid of 2 iterations? Thanks.
Use Linq and string.Join to iterate once and avoid SubString:
var data = new List<(string, string)> { ("d1", "d2"), ("d3", "d4"), };
var exclude = new List<string>();
var filters = string.Join(" OR ", data.Select(entity => {
exclude.Add($"Name1 != '{entity.Item1}'");
return $"(Name1 = '{entity.Item1}' AND Name2 = '{entity.Item1}')";
}));
string final = $"{filters} OR ({string.Join(" AND ", exclude)})";
You can have two filter strings which you build up simultaneously and then combine at the end:
string filter = "";
string filter2 = "";
var data = new List<(string, string)>
{
("d1", "d2"), ("d3", "d4"),
};
foreach(var entity in data)
{
filter += $"(Name1 = '{entity.Item1}' AND Name2 = '{entity.Item1}') OR ";
filter2 += $"Name1 != '{entity.Item1}' AND ";
}
filter2 = filter2.Substring(0, filter2.LastIndexOf("AND")).TrimEnd();
string final = $"{filter}({filter2})";
Live demo: https://dotnetfiddle.net/TGr6Jz
In the code below, I would like the return from GetChainDetails to go where i have "I WANT MY LIST HERE" in GetChains method. Not sure how to accomplish or what other way to do this.
public static IEnumerable GetChains(int actGroupid, int dispid)
{
EEDBEntities db = new EEDBEntities();
var query = from c in db.Chains
where c.Activity_Basis.activity_group_id == actGroupid && c.Activity_Basis.discipline_id == dispid
select new
{
ChainID = c.ChainID,
ChainDesc = #"<span data-toggle=""tooltip"" title =""" + I WANT MY LIST HERE + #""">" + c.ChainID + "</span>"
};
return query.ToList();
}
public string GetChainDetails(string chainID)
{
string sStep = null;
var chainDetailList = from c in db.Chains_Detail
where c.chainID == chainID
orderby c.Order
select new
{
Order = c.Order,
Step = c.Step
};
foreach (var oItem in chainDetailList.ToList())
{
sStep = sStep + "\n" + oItem.Order + ": " + oItem.Step;
}
return sStep;
}
Your method public string GetChainDetails(string chainID) is not static. Perhaps this is the reason you are getting error. Make it static and try and run the code.
public static string GetChainDetails(string chainID)
Also you can follow this approach :
class X
{
public int Property1;
public int Property2;
public string ChainID;
public string MyListToolTipText;
}
class Y
{
public string ChainID;
public string ChainDesc;
}
And your main code
class Program
{
static void Main()
{
var myResult = GetChains(1, 1);
foreach (var result in myResult)
{
result.ChainDesc = GetChainDetails(result.ChainID);
}
//you can use either foreach or linq
//var m = myResult.Select(result => result = new Y { ChainID = result.ChainID, ChainDesc = GetChainDetails(result.ChainDesc) });
}
public static IEnumerable<Y> GetChains(int actGroupid, int dispid)
{
var Chains = new List<X>();
var query = from c in Chains
where c.Property1 == actGroupid && c.Property2 == dispid
select new Y
{
ChainID = c.ChainID,
ChainDesc = #"<span data-toggle=""tooltip"" title =""" + c.MyListToolTipText + #""">" + c.ChainID + "</span>"
};
return query.ToList<Y>();
}
public static string GetChainDetails(string chainID)
{
string sStep = null;
var chainDetailList = from c in db.Chains_Detail
where c.chainID == chainID
orderby c.Order
select new
{
Order = c.Order,
Step = c.Step
};
foreach (var oItem in chainDetailList.ToList())
{
sStep = sStep + "\n" + oItem.Order + ": " + oItem.Step;
}
return sStep;
}
}
Hence after calling GetChains, I am modifying each member property.
I'm using System.Linq.Dynamic to make dinanmico where in my research. In the code below I try to filter by Funcao, but returns the error:
No property or field 'Funcao' exists in type 'ASO'
How do I filter by an alias of my Linq?
CODE
public static ResultadoListagemPadrao Grid(int iniciarNoRegistro, int qtdeRegistro, string orderna, string ordenaTipo, string filtro, int filtroID, UsuarioLogado usuarioLogado)
{
var where = "";
var id = 0;
if (filtroID > 0)
where += " FuncionarioID == " + filtroID.ToString();
else
{
if (int.TryParse(filtro, out id))
where += " ASOID == " + id.ToString();
if (filtro != null)
where += " Funcao.Contains(#0) ";
}
using (var db = new ERPContext())
{
var resultado = new ResultadoListagemPadrao();
resultado.TotalRegistros = db.ASO.Total(usuarioLogado.EmpresaIDLogada);
resultado.TotalRegistrosVisualizados = db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable().Where(where, filtro).Count();
resultado.Dados =
(from a in db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable()
select new
{
a.ASOID,
a.FuncionarioID,
Cliente = a.Funcionario.Cliente.Pessoa.Nome,
Setor = a.FuncionarioFuncao.Funcao.Setor.Descricao,
Funcao = a.FuncionarioFuncao.Funcao.Descricao,
Funcionario = a.Funcionario.Pessoa.Nome,
a.DtASO,
a.Status
})
.Where(where, filtro)
.OrderBy(orderna + " " + ordenaTipo)
.Skip(iniciarNoRegistro)
.Take(qtdeRegistro)
.ToArray();
return resultado;
}
}
Issue is this line db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable().Where(where, filtro)
Your class ASO doesn't have a property Funcao.
Try remove the Where on that line. Try this...
var resultado = new ResultadoListagemPadrao();
resultado.TotalRegistros = db.ASO.Total(usuarioLogado.EmpresaIDLogada);
var query = (from a in db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable()
select new
{
a.ASOID,
a.FuncionarioID,
Cliente = a.Funcionario.Cliente.Pessoa.Nome,
Setor = a.FuncionarioFuncao.Funcao.Setor.Descricao,
Funcao = a.FuncionarioFuncao.Funcao.Descricao,
Funcionario = a.Funcionario.Pessoa.Nome,
a.DtASO,
a.Status
})
.Where(where, filtro);
resultado.TotalRegistrosVisualizados = query.Count();
resultado.Dados = query
.OrderBy(orderna + " " + ordenaTipo)
.Skip(iniciarNoRegistro)
.Take(qtdeRegistro)
.ToArray();
return resultado;
Please in future translate your code.
I am using CRM 4 and the SDK to grab cases like so:
public List<Case> GetCases()
{
List<Case> cases = new List<Case>();
#region Retrieve Resolved Cases
try
{
InitSession();
RetrieveMultipleRequest req = new RetrieveMultipleRequest();
req.ReturnDynamicEntities = true;
//QueryExpression says what entity to retrieve from, what columns we want back and what criteria we use for selection
QueryExpression qe = new QueryExpression();
qe.EntityName = EntityName.incident.ToString();
List<string> attributes = new string[] {
"incidentid","title" ,"description", "ticketnumber", "statuscode",
"kez_allocatedhours",
"customerid",
"casetypecode"
}.ToList();
//columns to retireve
ColumnSet AvailabilityColumnSet = new ColumnSet();
AvailabilityColumnSet.Attributes = attributes.ToArray();
qe.ColumnSet = AvailabilityColumnSet;
//filter
FilterExpression fe = new FilterExpression();
fe.FilterOperator = LogicalOperator.And;
//condtion for filter
ConditionExpression isResolved = new ConditionExpression();
isResolved.AttributeName = "statuscode";
isResolved.Operator = ConditionOperator.NotEqual;
isResolved.Values = new string[] { "5" };
fe.Conditions = new ConditionExpression[] { isResolved }; //Add the conditions to the filter
qe.Criteria = fe; //Tell the query what our filters are
req.Query = qe; //Tell the request the query we want to use
//retrieve entities
RetrieveMultipleResponse resp = svc.Execute(req) as RetrieveMultipleResponse;
if (resp != null)
{
BusinessEntity[] rawResults = resp.BusinessEntityCollection.BusinessEntities;
List<DynamicEntity> castedResults = rawResults.Select(r => r as DynamicEntity).ToList();
foreach (DynamicEntity result in castedResults)
{
string id = GetProperty(result, "incidentid");
string title = GetProperty(result, "title");
string description = GetProperty(result, "description");
string ticket = GetProperty(result, "ticketnumber");
string customer = GetProperty(result, "customerid");
int statuscode = -1;
string statusname = "";
double estHours = 0.0;
string casetype = "";
int casetypecode = -1;
Property prop = result.Properties.Where(p => p.Name == "statuscode").FirstOrDefault();
if (prop != null)
{
StatusProperty status = prop as StatusProperty;
if (status != null)
{
statuscode = status.Value.Value;
statusname = status.Value.name;
}
}
prop = result.Properties.Where(p => p.Name == "kez_allocatedhours").FirstOrDefault();
if (prop != null)
{
CrmFloatProperty fl = prop as CrmFloatProperty;
if (fl != null)
{
estHours = fl.Value.Value;
}
}
prop = result.Properties.Where(p => p.Name == "casetypecode").FirstOrDefault();
if (prop != null)
{
PicklistProperty fl = prop as PicklistProperty;
if (fl != null)
{
casetype = fl.Value.name;
casetypecode = fl.Value.Value;
}
}
Case c = new Case();
c.ID = id;
c.Title = title;
c.Description = description;
c.StatusCode = statuscode;
c.StatusName = statusname;
c.TicketNumber = ticket;
c.CustomerName = customer;
c.EstimatedHours = estHours;
c.Type = casetype;
c.TypeCode = casetypecode;
bool allowedThroughStat = true;
bool allowedThroughType = true;
var userStatuses = SettingsManager.Get("CRMUserStatusReasons").Split(';').ToList().Where(p => p.Length > 0).ToList();
var userTypes = SettingsManager.Get("CRMUserCaseTypes").Split(';').ToList().Where(p => p.Length > 0).ToList();
if(userStatuses.Count > 0 && !userStatuses.Contains(c.StatusCode.ToString()))
{
allowedThroughStat = false;
}
if (userTypes.Count > 0 && !userTypes.Contains(c.TypeCode.ToString()))
{
allowedThroughType = false;
}
if(allowedThroughStat && allowedThroughType)
cases.Add(c);
}
}
}// end try
catch (Exception)
{
return null;
// The variable 'e' can access the exception's information.
// return "Error Message: " + e.Message.ToString() + " | Stack Trace: " + e.StackTrace.ToString();
}
return cases;
#endregion
}
However, now I need to be able to change the status and title of a case from C# given its incidentid.
Ive looked at the SDK docs and cannot find an example of this.
Anyone work with this before?
Thanks
Simply put, above is code to read an incident. Could I get an example of writing an incident field, Just one. Ex: How could I change the title of an incident.
You can call the Update method on the CrmService. Here is the SDK article.
Case c = new Case();
c.ID = id;
c.Title = title;
svc.Update(c);
To change the state of an entity you use the setstaterequest. If you want to do it to a dynamic entity there's a description in this blog
the below way i did the search with lucene.net. this routine search multiple word against all index field called "Title", "Description", "Url", "Country" .
i need to know how can i give a condition like where country='UK' or country='US'
i want that multiple word should be search like below but i want to add one more clause that when country is UK. so please guide me what to add in my code.
if (!string.IsNullOrEmpty(multiWordPhrase))
{
string[] fieldList = { "Title", "Description", "Url" };
List<BooleanClause.Occur> occurs = new List<BooleanClause.Occur>();
foreach (string field in fieldList)
{
occurs.Add(BooleanClause.Occur.SHOULD);
}
searcher = new IndexSearcher(_directory, false);
Query qry = MultiFieldQueryParser.Parse(Version.LUCENE_29, multiWordPhrase, fieldList, occurs.ToArray(), new StandardAnalyzer(Version.LUCENE_29));
TopDocs topDocs = searcher.Search(qry, null, ((PageIndex + 1) * PageSize), Sort.RELEVANCE);
ScoreDoc[] scoreDocs = topDocs.ScoreDocs;
int resultsCount = topDocs.TotalHits;
list.HasData = resultsCount;
StartRecPos = (PageIndex * PageSize) + 1;
if (topDocs != null)
{
for (int i = (PageIndex * PageSize); i <= (((PageIndex + 1) * PageSize)-1) && i < topDocs.ScoreDocs.Length; i++)
{
Document doc = searcher.Doc(topDocs.ScoreDocs[i].doc);
oSr = new Result();
oSr.ID = doc.Get("ID");
oSr.Title = doc.Get("Title");
oSr.Description = doc.Get("Description");
//oSr.WordCount = AllExtension.WordCount(oSr.Description, WordExist(oSr.Title, multiWordPhrase));
string preview =
oSr.Description = BBAReman.AllExtension.HighlightKeywords(oSr.Description, multiWordPhrase); //sr.Description;
oSr.Url = doc.Get("Url");
TmpEndRecpos++;
list.Result.Add(oSr);
}
}
thanks
Look up BooleanQuery
if (!string.IsNullOrEmpty(multiWordPhrase))
{
BooleanQuery bq = new BooleanQuery();
string[] fieldList = { "Title", "Description", "Url" };
List<BooleanClause.Occur> occurs = new List<BooleanClause.Occur>();
foreach (string field in fieldList)
{
occurs.Add(BooleanClause.Occur.SHOULD);
}
Query qry = MultiFieldQueryParser.Parse(Version.LUCENE_29, multiWordPhrase, fieldList, occurs.ToArray(), new StandardAnalyzer(Version.LUCENE_29));
bq.Add(qry,BooleanClause.Occur.Must);
//this is the country query (modify the Country field name to whatever you have)
string country = "UK";
Query q2 = new QueryParser(Version.LUCENE_CURRENT, "Country", analyzer).parse(country);
bq.Add(q2,BooleanClause.Occur.Must);
searcher = new IndexSearcher(_directory, false);
TopDocs topDocs = searcher.Search(bq, null, ((PageIndex + 1) * PageSize), Sort.RELEVANCE);
ScoreDoc[] scoreDocs = topDocs.ScoreDocs;
int resultsCount = topDocs.TotalHits;
list.HasData = resultsCount;
StartRecPos = (PageIndex * PageSize) + 1;
if (topDocs != null)
{
//loop through your results
}