I am starting off with azure document db. I was trying to update an existing document. When I use the following query everything works:
dynamic Team2Doc = client.CreateDocumentQuery<Document>(documentCollection.DocumentsLink).Where(d => d.Id == "t002").AsEnumerable().FirstOrDefault();
Team2Doc.TeamName = "UPDATED_TEAM_2";
await client.ReplaceDocumentAsync(Team2Doc);
but if use the below code:
dynamic Team2Doc = client.CreateDocumentQuery<Document>(documentCollection.DocumentsLink).Where(d => d.TeamName== "team1").AsEnumerable().FirstOrDefault();
Team2Doc.TeamName = "UPDATED_TEAM_2";
await client.ReplaceDocumentAsync(Team2Doc);
I get this error:
"The best overloaded method match for
'Microsoft.Azure.Documents.Client.DocumentClient.ReplaceDocumentAsync(Microsoft.Azure.Documents.Document,
Microsoft.Azure.Documents.Client.RequestOptions)' has some invalid
arguments"
Is there anyway to retrieve a document by one of the properties and update the document?
The where clause is trying to query the property TeamName which does not exist in Document class.
Changing the type of the queryable to your data model should fix it.
For example, say you have the following data model:
public class EmployeeDocument : Document
{
// Other properties that you may have similarly defined ....
public class string TeamName
{
get
{
return this.GetValue<string>("TeamName");
}
set
{
this.SetValue("TeamName", value);
}
}
}
Then you can modify your query like this:
var team2Doc = client.CreateDocumentQuery<EmployeeDocument>(documentCollection.DocumentsLink).Where(d => d.TeamName== "team1").AsEnumerable().FirstOrDefault();
team2Doc.TeamName = "UPDATED_TEAM_2";
await client.ReplaceDocumentAsync(team2Doc);
Note that you have to use the EmployeeDocument, instead of the Document class, while creating the document queryable. That will let you query on EmployeeDocument properties.
SQL Version
Creating a document model for each of your existing data models may not be feasible if you have a large number of data models. In that case you may want to try out the SQL query syntax.
Refer to Aravind's answer in this post. The example he uses is for deleting documents, but it can be easily modified to update them too.
You can also create a model with Id:
public class Employee
{
[JsonPropery("id")]
public class string Id { get; set; }
public class string TeamName { get; set; }
}
And then replace the document using it's Id:
var employee= client
.CreateDocumentQuery<Employee>(documentCollection.DocumentsLink)
.Where(d => d.TeamName== "team1")
.AsEnumerable()
.FirstOrDefault();
employee.TeamName = "team2";
var documentUri = UriFactory.CreateDocumentUri(databaseName, collectionName, employee.Id);
await client.ReplaceDocumentAsync(employee);
Related
Before anyone marks this question as a duplicate of Get _id of an inserted document in MongoDB? please read the whole question.
I am developing a ASP.NET Core API app with MongoDB driver.
The problem I am facing is that after inserting a document in the database the Id property of the Post class is not assigned the id generated by MongoDB.
I found few questions where they solved it using the annotations/attributes in the class but, I am developing a pattern where domain classes don't have any persistence knowledge.
I have created the entity class without annotations:
public class Post
{
public string Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
And defined mapping using BsonClassMap:
BsonClassMap.RegisterClassMap<Domain.Entities.Post>(x =>
{
x.AutoMap();
x.MapIdField(x => x.Id)
.SetSerializer(new StringSerializer(BsonType.ObjectId))
.SetIgnoreIfDefault(true);
});
Here's is the code:
public async Task Create(Domain.Entities.Post entity, CancellationToken cancellationToken)
{
async Task Create()
{
await Post.InsertOneAsync(entity);
}
await Create();
var e = entity;
}
When I inspect the entity the Id property is null.
So, how do I get id when using the BsonClassMap?
Currently, your code knows how to read Ids when they come as ObjectId from the database but still needs help when it comes to generating ids on the client side,
The missing part is SetIdGenerator method invocation, try:
BsonClassMap.RegisterClassMap<Post>(x =>
{
x.AutoMap();
x.MapIdField(x => x.Id)
.SetIdGenerator(StringObjectIdGenerator.Instance)
.SetSerializer(new StringSerializer(BsonType.ObjectId))
.SetIgnoreIfDefault(true);
});
Now ObjectIds will be generated and turned into string on the client side so you should be able to see them when you hover over e variable.
Details here.
I am exposing my Table via the following method:
public static class TableCacheService
{
public static IEnumerable<Myentity> Read()
{
var acc = new CloudStorageAccount(
new StorageCredentials("account", "mypass"), false);
var tableClient = acc.CreateCloudTableClient();
var table = tableClient.GetTableReference("Myentity");
return table.ExecuteQuery(new TableQuery<Myentity>());
}
}
Here's a usage example:
var nodeHasValue = TableCacheService.Read()
.Where(x => note.ToLower().Contains(x.RowKey.ToLower()))
.Any();
But supposedly x.RowKey is null!
It looks like there are 2 members both called RowKey. One of them is a TableEntity:
How do I access the RowKey that is non-null? Am I incorrectly querying the table?
It seems you have hiding properties RowKey and PartitionKey inside your Myentity class.
I guess your Myentity class has something like it:
public class Myentity: TableEntity
{
public new string RowKey { get; set; }
...
}
Pay attention to keyword new.
If you have this construction you need to delete this property.
More information about hiding and overriding you can find here.
Also please review work example with ATS (Azure Table Storage) is here.
I have a MVC4 application with a WebApi method which is getting entire table data from database. Now i want to extract only two columns from it. How can I do it?
I know that arrays will be used to do so but don't know the syntax in .net.
This is my WebAPi function which is getting the entire table data from the SQL server database:
namespace BRDCEP_MIS.Areas.BRDCEP.Controllers
{
public class WebApiController : ApiController
{
//api get method.
//[Route("WebApi/GetPscTargets")]
public HttpResponseMessage Get() {
using (ApplicationDbContext db = new ApplicationDbContext())
{
List<PscDistrictTargets> xx = new List<PscDistrictTargets>();
xx = db.PscDistrictTargetss.ToList();
//xx.ID = Convert.ToString(DATA);
HttpResponseMessage response = new HttpResponseMessage();
response = Request.CreateResponse(HttpStatusCode.OK, xx);
return response;
}
}
}
}
You can use the Select method and do a projection on only those properties you needed to an an object of your DTO/view model to represent this data, in your LINQ query.
So create a DTO class to represent the data you want with only those properties,
public class MyDto
{
public int TargetId { set; get; }
public string TargetName { set; get; }
}
Now update your LINQ query use the Select method to get only those properties and project those our dto object.
var items = db.PscDistrictTargetss
.Select(f => new MyDto { TargetName = f.Name,
TargetId = f.Id})
.ToList();
return Request.CreateResponse(HttpStatusCode.OK, items );
Assuming PscDistrictTargets entity class has a Name and Id property. Update that part based on your actual property names.
I got an .net core application that is pretty straight forward it is using REST to add and download objects to and from mongo db. Adding items works really well. Getting a list that contains all items aswell, but when I try to access one using id then everytime I get null. What should i change to make this piece of code work. It means get a Tool object from database using it unique ID when there's one matching in database.
Here's a object in database
Here's my repository class
private IMongoCollection<Tool> Tools => _database.GetCollection<Tool>("Tools");
public async Task<Tool> GetAsync(Guid id) =>
await Tools.AsQueryable().FirstOrDefaultAsync(tool => tool.Id == id);
Argument looks like that when I check it out in debugger "{ee1aa9fa-5d17-464c-a8ba-f685203b911f}"
Edit
Tool Class Properties
public Guid Id { get; protected set; }
public string Model { get; protected set; }
public string Brand { get; protected set; }
public string Type { get; protected set; }
public uint Box { get; protected set; }
Fixed check comments
Project on github
The easiest way to do this in C# MongoDB Driver is to set a global GuidRepresentation setting which can be found on the BsonDefaults object. This is a global setting and will effect all serialization/deserialization of GUIDs in to Bson Binary Objects.
BsonDefaults.GuidRepresentation = GuidRepresentation.PythonLegacy;
var collection = new MongoClient().GetDatabase("test").GetCollection<ClassA>("test");
var item = collection.Find(x => x.MyId == new Guid("ee1aa9fa-5d17-464c-a8ba-f685203b911f"))
.FirstOrDefault();
The second option is to convert the GUID manually from a LUUID to a CSUUID, for this there is a helper class within the MongoDB driver of GuidConverter, with this it converts the GUID in to byte[] which is normally used for storage but we can use it for our query.
BsonDefaults.GuidRepresentation = GuidRepresentation.CSharpLegacy;
var collection = new MongoClient().GetDatabase("test").GetCollection<ClassA>("test");
var luuid = new Guid("0798f048-d8bb-7048-bb92-7518ea4272cb");
var bytes = GuidConverter.ToBytes(luuid, GuidRepresentation.PythonLegacy);
var csuuid = new Guid(bytes);
var item = collection.Find(x => x.MyId == csuuid)
.FirstOrDefault();
I also noticed that you're using Robo 3T (formerly Robomongo), within this application you can set how GUIDs are displayed by going to Options -> Legacy UUID Encodings
When connecting to CRM 2013 is there a smart way to create a lambda expression that gets the entities who's GUID are in a List.
This code breaks on the Where clause and gives the error:
Invalid 'where' condition. An entity member is invoking an invalid property or method.
Code:
private List<UserInformationProxy> GetContactsFromGuidList(List<Guid> contactList)
{
var result = _serviceContext.ContactSet
.Where(x=> contactList.Contains((Guid) x.ContactId)) // this line breaks
.Select(x => new UserInformationProxy()
{
FullName = x.FullName,
Id = x.ContactId
})
.Distinct()
.ToList<UserInformationProxy>();
return result;
}
// return class
public class UserInformationProxy
{
public Guid? Id { get; set; }
public string FullName { get; set; }
public string DomainName { get; set; }
}
Currently I'm solving this by getting all the contacts from the ContactSet and sorting out the ones I want with a loop in my code. This works, but is quite slow as I need to get all 10000 contacts instead of sending the Guids of the 40 Im actually interested in to the SQL server.
QueryExpressions support an In operator, so this should work just fine:
private List<UserInformationProxy> GetContactsFromGuidList(List<Guid> contactList)
{
var qe = new QueryExpression(Contact.EntityLogicalName);
qe.ColumnSet = new ColumnSet("fullname", "contactid")
qe.Criteria.AddCondition("contactid", ConditionOperator.In, list.Cast<Object>().ToArray());
qe.Distinct = true;
var results = service.RetrieveMultiple(qe).Entities.Select (e => e.ToEntity<Contact>()).
Select(x => new UserInformationProxy()
{
FullName = x.FullName,
Id = x.ContactId
});
return results;
}
On a side note, every Contact has to have an Id that is not empty, so there is no need to check for it.
EDIT: It is possible to accomplish using a single query, Daryl posted an answer with the right code.
Other (not so clever) alternatives are:
Retrieve all the records and after check the Guids
Do a single retrieve for each Guid
Because are only 40 records, I suggest to use late-bound to retrieve the records, in order to choose the minimal ColumnSet.
Useful links related to this issue:
Another question regarding Dynamics CRM LINQ limitations
Performance test Early Bound vs Late Bound