How to search List of name which are present in cosmos documents - azure

I have a list of name. I need to find which name is present in FirstName or LastName Property of Document in Collection.
I had tried the Linq query to archive this but it through error ("Object reference not set to an instance of an object.").
public class UserDoc
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DocumentType { get { return "userdoc"; } private set { } }
}
List<string> Names = new List<string>() { "satya", "singh" };
IEnumerable<UserDoc> Users = await _dBRepository.GetItemsAsync<UserDoc>
(x => (Names.Contains(x.FirstName + " " + x.LastName))&& x.DocumentType == "userdoc");
public async Task<IEnumerable<T>> GetItemsAsync<T>(Expression<Func<T, bool>> predicate) where T : class
{
IDocumentQuery<T> query = _client.CreateDocumentQuery<T>(documentCollectionUri:
UriFactory.CreateDocumentCollectionUri(databaseId: _databaseId, collectionId: _collectionId),
feedOptions: new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true })
.Where(predicate)
.AsDocumentQuery();
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}

According to your description. You code should be modified as below:
IEnumerable<UserDoc> Users = await _dBRepository.GetItemsAsync<UserDoc>
(x => (Names.Contains(x.FirstName)|| Names.Contains(x.LastName))&& x.DocumentType == "userdoc");
I have tested the code and it worked.
According to your error message, i think the the most likely reason is that the object _client point to Null, please check it and try again.

Related

How can i execute filter from our JSON filter JSON?

I have a vue3 datagrid and I want to fill the data in this grid with filter by API. At the same time, I want to send the filter fields in the grid to the API as JSON and execute them according to this filter on the API side. How can I do this with AutoQuery?
[Route("/GetConnectors", "POST")]
public class GetConnectors : QueryDb<Connector>
{
public string Id { get; set; }
public string PageParameterJson { get; set; }
}
public class Connector
{
[PrimaryKey]
[AutoIncrement]
public long PKey { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
public class PageParameters
{
public string Field { get; set; }
public string Operand { get; set; }
public string Value { get; set; }
public string Type { get; set; }
}
It's an example PageParameter JSON;
[
{
"Field":"Name",
"Operand":"cn"//Contains
"Value":"test",
"Type":"string"
},
{
"Field":"Id",
"Operand":"eq"//Equal
"Value":"2",
"Type":"string"
}
]
public async Task<object> Any(GetConnectors query)
{
using var db = AutoQuery.GetDb(query, base.Request);
var filters = query.PageParameters.FromJson<List<PageParameter>>();
//How can I execute query with for CreateQuery?
var q = AutoQuery.CreateQuery(query, Request, db);
var sql = q.PointToSqlString();
return await AutoQuery.ExecuteAsync(query, q, base.Request, dbConnection);
}
Best Regards
i can't execute dynamic filters from server-side datagrid
The AutoQuery.CreateQuery returns OrmLite's Typed SqlExpression which has a number of filtering options inc .Where(), .And(), .Or(), etc.
So you should be able to populate it with something like:
foreach (var filter in filters)
{
var type = filter.Type switch
{
"string" => typeof(string),
_ => throw new NotSupportedException($"Type {filterType}")
};
var value = filter.Value.ConvertTo(type);
if (filter.Operand == "eq")
{
q.And(filter.Field + " = {0}", value)
}
else if (filter.Operand == "cn")
{
q.And(filter.Field + " LIKE {0}", $"%{value}%")
}
else throw new NotSupportedException(filter.Operand);
}
Note: I've rewritten API to be async as you should never block on async methods.

asp.net core delete everything with certain number

I want to delete all vragen(questions in english) with the classID for example number 5. It is possible to give a vraagID and a classID and the server deletes the question if it matches. But I want to delete all matching questions with only one request. Is this possible?
namespace AspIdentityServer.data
{
public class Vraag :Conversatie
{
public int VraagID { get; set; }
public int classID { get; set; }
public string Titel { get; set; }
public ICollection<Antwoord> Antwoord { get; set; }
public Vak Vak { get; set; }
}
}
--
// DELETE: api/Vraags/1/alles/5
[AllowAnonymous]
[HttpDelete("{id}/alles/{vakID}")]
public async Task<IActionResult> DeleteAlleVragen([FromRoute] int id, int vakID) {
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var vraag = await _context.Vraag.SingleOrDefaultAsync(m => m.VraagID == id);
if (vraag.classID == vakID)
{
_context.Vraag.Remove(vraag);
await _context.SaveChangesAsync();
}
return Ok(vraag);
}
You can always use the ExecuteSqlCommandAsync to execute your custom SQL queries. So write a single delete statements with appropriate where clause which will handle many rows as needed.
Here is a quick example
object[] paramsArray =
{
new SqlParameter
{
ParameterName = "#vraagId",
SqlDbType = SqlDbType.Int,
Value = id
},
new SqlParameter
{
ParameterName = "#classId",
SqlDbType = SqlDbType.Int,
Value = vakID
}
};
const string q = "DELETE FROM VraagWHERE VraagID=#vraagId and ClassId=#classId";
await _context.Database.ExecuteSqlCommandAsync(q, paramsArray);
Update the SQL statemenets and parameters as needed.

ArangoDb.Net upsert always insert

I'm making a small application with CRUD functions with ArangoDatabase and its driver:
http://www.arangoclient.net/
Here is my code:
var insert = new Account
{
Email = "email01#gmail.com",
FirstName = "Adam",
LastName = "Smith"
};
var update = new Account
{
Email = "email01#gmail.com",
FirstName = "John",
LastName = "Peterson"
};
using (var arangoDatabase = new ArangoDatabase(new DatabaseSharedSetting()
{
Url = "http://127.0.0.1:8529/",
Database = "_system",
Credential = new NetworkCredential()
{
UserName = "root",
Password = "xvxvc"
}
}))
{
arangoDatabase.Query()
.Upsert(_ => new Account() {Email = insert.Email},
_ => insert, ((aql, x) => update))
.In<Account>()
.Execute();
}
For the first time running, [insert] object is added to database.
Therefore, my database now is :
But at the second time of running code, it throws me an error :
unique constraint violated (while executing). ErrorNumber: 1210 HttpStatusCode: 409
The question is: What is my problem and how to solve it?
Thank you,
Problem could be upsert search expression serialization:
Assume Account class definition is:
public class Account
{
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
upsert search expression: new Account() {Email = insert.Email} will serializes to:
{ Email: "email01#gmail.com", FirstName: null, LastName: null }
but what is expected is:
{ Email: "email01#gmail.com" }
Since search expression will never found a document, then insert will occur and you get unique constraint violated.
There are two solution to avoid serializing FirstName and LastName members:
One is we could use Json.net JsonProperty attribute to ignore nulls in serialization:
public class Account
{
public string Email { get; set; }
[Newtonsoft.Json.JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string FirstName { get; set; }
[Newtonsoft.Json.JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string LastName { get; set; }
}
And the other way is to use an anonymous object for search expression:
arangoDatabase.Query()
.Upsert(_ => new Account() {Email = insert.Email}
// should be
arangoDatabase.Query()
.Upsert(_ => new {Email = insert.Email}
One note about using anonymous object is that Email member could resolve to something else base on what you specify for its naming convention, for example:
public class Account
{
[DocumentProperty(Identifier = IdentifierType.Key)]
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
If you specify Email as a Key identifier, then you should use _key in the anonymous object:
arangoDatabase.Query()
.Upsert(_ => new { _key = insert.Email }

foreach collection reference type nested property update

I see numerous examples on foreach collection reference type property update, but not quite what I am struggling with. What if you want to update a property of a property of the reference type item? like so:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public EmployeeType EmpType { get; set; }
}
public class EmployeeType
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Class1
{
private IList<Employee> existingEmp;
public void edit()
{
var dbEmployees = GetExistingEmployees();
IList<Employee> employees = new List<Employee> {
new Employee{ Id = 1, Name="me", EmpType = new EmployeeType { Id = 1}},
new Employee{ Id = 2, Name="me again", EmpType = new EmployeeType { Id = 2}}
};
foreach (var emp in employees)
{
foreach (var oldEmp in dbEmployees)
{
if (emp.Id == oldEmp.Id)
{
UpdateChanges(emp, oldEmp);
existingEmp.Add(oldEmp);
}
}
}
}
private void UpdateChanges(Employee emp, Employee oldEmp){
if (oldEmp.EmpType.Id != emp.EmpType.Id)
{
LogChange();
oldEmp.EmpType.Id = emp.EmpType.Id;
}
}
private void LogChange()
{
throw new NotImplementedException();
}
//data access layer
public IList<Employee> GetExistingEmployees()
{
throw new NotImplementedException();
}
}
The issue here is the last employee in the collection if his/her employee type property Id changed in a ddl, updating it will cascade to all other employees' emp type in the collection. That is nutts. Due to the logging requirement I can not use lambda or other fancy construct. I need hep with fixing this with in foreach or for loops.
EDIT:
As expected the same code structure works somewhere else in my application. I don't get the last item's property updating bleeding to other items' properties.
I solved this using a hacky approach:
private void UpdateChanges(Employee emp, Employee oldEmp){
var oldEmpTemp = GetEmployeeById(oldEmp.Id);
if (oldEmp.EmpType.Id != emp.EmpType.Id)
{
LogChange();
oldEmpTemp.EmpType.Id = emp.EmpType.Id;
}
//instead of updating the collection items
// and bulk updating in the db, update directly in the db
UpdateEmployee(oldEmpTemp);
}
But still can't explain why it's not working for this instance.

Neo4jClient is not returning properties for a node in .Return

I am trying to use Neo4jClient (and am new to C#) to build and retrieve data from Neo4j. First, I build the items and relations to a search:
NodeReference<Search> searchNode = client.Create(searches[i]);
itmNode = client.Create(items[j], new IRelationshipAllowingParticipantNode<Item>[0],
new[]
{
new IndexEntry("Item")
{
{"Type", items[j].Type },
{"ItemDescription", items[j].ItemDescription },
{"ItemNumber", items[j].ItemNumber }
}
});
client.CreateRelationship(itmNode, new SearchedFor(searchNode, 1));
Then, I am testing the retrieval of the node back from Neo4j:
var results = client.Cypher.Start("n", itemDict[firstitem])
.Match("n-[r]->()<-[r2]-other")
.Return<Node<Item>>("other")
.Results;
var node6 = ((IRawGraphClient)client).ExecuteGetCypherResults<Node<Item>>(new Neo4jClient.Cypher.CypherQuery("start n=node(6) return n;", null,Neo4jClient.Cypher.CypherResultMode.Set)).Select(un => un.Data);
"results" returns the 2 nodes that are related to node(6). "node6" is other code I found that I thought would return node 6. Both of these return the nodes, but the properties returned are all blank. I can see the properties in the Neo4j Monitoring Tool, but not when they are returned using Neo4jClient. Am I missing something in how I am setting up the nodes, or on how I am retrieving the data?
My object return shows Data.ItemDescription="", Data.ItemNumber=0, Reference=Node 5
Adding the "Select(un => un.Data)" after .Results did not work like I saw in other examples like this
Please let me know if you need more information.
Neo4jClient version 1.0.0.579
Neo4j version 1.8.2
Here is the item class:
public class Item
{
private string _name;
private string _desc;
private long _id;
public Item(string name, string desc, long id)
{
_name = name;
_desc = desc;
_id = id;
}
public Item()
{
_name = "";
_desc = "";
_id = 0;
}
public long ItemNumber
{
get
{
return _id;
}
}
public string ItemDescription
{
get
{
return _desc;
}
}
public string Type
{
get
{
return "Item";
}
}
}
Making it work
The issue is that your Item class has no setters exposed. There's no way for us to set those properties , so we ignore them.
You can delete half your code, and it'll work. :)
public class Item
{
public long ItemNumber { get; set; }
public string ItemDescription { get; set; }
public string Type { get ; set; }
}
Making it better
Replace this:
NodeReference<Search> searchNode = client.Create(searches[i]);
itmNode = client.Create(items[j], new IRelationshipAllowingParticipantNode<Item>[0],
new[]
{
new IndexEntry("Item")
{
{"Type", items[j].Type },
{"ItemDescription", items[j].ItemDescription },
{"ItemNumber", items[j].ItemNumber }
}
});
client.CreateRelationship(itmNode, new SearchedFor(searchNode, 1));
with this:
var searchNode = client.Create(searches[i]);
var itemNode = client.Create(
items[j],
new[] { new SearchedFor(searchNode, 1) }
new[]
{
new IndexEntry("Item")
{
{"Type", items[j].Type },
{"ItemDescription", items[j].ItemDescription },
{"ItemNumber", items[j].ItemNumber }
}
});
That will create that second node, and the relationship, in a single call.

Resources