When I query the status data from Azure Cosomos DB, I encountered a problem and can't find solution.
Code:
public static async Task<List<StatusData>> GenStatusData()
{
var sqlQueryText = $"Select * from (SELECT c.task,c.status, count(c.task) as countnum FROM c group by c.status, c.task ) as e order by e.task";
QueryDefinition queryDefinition = new QueryDefinition(sqlQueryText);
List<StatusData> models = new List<StatusData>();
//Microsoft.Azure.Cosmos.Query.Core.Pipeline.CrossPartition.OrderBy.OrderByQueryResult.get_Rid()
var queryResultSetIterator = container.GetItemQueryIterator<StatusData>(queryDefinition);
while (queryResultSetIterator.HasMoreResults)
{
FeedResponse<StatusData> currentResultSet = await queryResultSetIterator.ReadNextAsync();
//Console.WriteLine(currentResultSet.Count);
foreach (StatusData model in currentResultSet)
{
models.Add(model);
//Console.WriteLine("\tRead {0}\n", model);
}
}
return await Task.FromResult(models);
}
Issue Encountered:
An unhandled exception occurred while processing the request.
InvalidOperationException: Underlying object does not have an '_rid' field.
Microsoft.Azure.Cosmos.Query.Core.Pipeline.CrossPartition.OrderBy.OrderByQueryResult.get_Rid()
Related
I am implementing a multi-tenant application using cosmosDB. I am using partition keys to separate multiple users data. Following best practices i am trying to allow each tenant to have its own db access token.
I create a user and permission and use the created token to access the partition. But I get the following error:
Partition key provided either doesn't correspond to definition in the collection or doesn't match partition key field values specified
in the document.
ActivityId: 1659037a-118a-4a2d-8615-bb807b717fa7, Microsoft.Azure.Documents.Common/1.22.0.0, Windows/10.0.17134
documentdb-netcore-sdk/1.9.1
My code goes as follows:
Constructor Initiates the client
public Projects (CosmosDbConfig cosmosConfig)
{
config = cosmosConfig;
client = new DocumentClient(new Uri(config.Endpoint), config.AuthKey);
collectionUri = UriFactory.CreateDocumentCollectionUri(config.Database, config.Collection);
config.AuthKey = GetUserToken().Result;;
client = new DocumentClient(new Uri(config.Endpoint), config.AuthKey);
}
The get user function creates the user and retrieves the token. User Ids are partition keys.
private async Task<string> GetUserToken()
{
User user = null;
try
{
try
{
user = await client.ReadUserAsync(UriFactory.CreateUserUri(config.Database, config.PartitionKey));
var permission = await GetorCreatePermission(user, config.Collection, config.PartitionKey);
return permission.Token;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
if (user == null)
{
user = new User
{
Id = config.PartitionKey
};
user = await client.CreateUserAsync(UriFactory.CreateDatabaseUri(config.Database), user);
var permission = await GetorCreatePermission(user, config.Collection, config.PartitionKey);
return permission.Token;
}
else
{
throw new Exception("");
}
}
catch (Exception ex)
{
throw ex;
}
}
Permission are done per collections and holds the collection name as ID since Ids are unique per user.
private async Task<Permission> GetorCreatePermission(User user,
string collection,
string paritionKey)
{
var permDefinition = new Permission
{
Id = collection,
PermissionMode = PermissionMode.All,
ResourceLink = collectionUri.OriginalString,
ResourcePartitionKey = new PartitionKey(paritionKey),
};
var perms = client.CreatePermissionQuery(user.PermissionsLink).AsEnumerable().ToList();
var perm = perms.FirstOrDefault(x => x.Id == collection);
if (perm != null)
{
return perm;
}
else
{
var result = await client.CreatePermissionAsync(user.SelfLink, permDefinition);
perm = result.Resource;
return perm;
}
}
The create function utilizes the new client and this where the error occurs.
public async Task<string> Create(Project p)
{
var result = await client.CreateDocumentAsync(collectionUri, p, new RequestOptions()
{ PartitionKey = new PartitionKey(config.PartitionKey),
});
var document = result.Resource;
return document.Id;
}
Since error says that partition key is incorrect i can suggest you try define partition key pathes while creating collection:
var docCollection = new DocumentCollection();
docCollection.Id = config.CollectionName;
docCollection.PartitionKey.Paths.Add(string.Format("/{0}", config.PartitionKey );
collectionUri = UriFactory.CreateDocumentCollectionUri(config.Database, docCollection);
I have a bit of code that I'm using to pull items from a database one at a time. On each get, it updates the status of the row to indicate that it has been retrieved so as to not retrieve the same row multiple times.
The below code is run from a backend service serving a Web API. Sometimes when multiple requests come in, it will return the same row (tasks with the same ID).
I was under the impression that having a transaction around it would mean that an update from one of the runs would preclude the row from being returned by a second query.
Any help would be appreciated.
public async Task<TaskDetail> GetTask()
{
using (var db = new SqlConnection(""))
{
using (var tran = db.BeginTransaction())
{
try
{
var sql = $#"
SELECT TOP 1 * FROM
(SELECT TOP 150 t.*
FROM Task t
INNER JOIN TaskStatus ts ON t.Id = ts.TaskId AND ts.Status = #taskStatus) t
ORDER BY NEWID();";
var chosen = await db
.QuerySingleOrDefaultAsync<TaskDetail>(
sql,
param: new
{
taskStatus = TaskStatusEnum.Ready
},
transaction: tran
);
if (chosen == null)
{
throw new InvalidOperationException();
}
var expiry = await db.ExecuteAsync("UPDATE TaskStatus SET Status = #status WHERE TaskId = #taskId", new {status = TaskStatusEnum.Done, taskId = chosen.TaskId}, tran);
tran.Commit();
return chosen;
}
catch
{
tran.Rollback();
throw;
}
}
}
}
A few wrong configurations can be the reason;
1- Check the SQL Server isolation level, be careful about dirty reads.
2- Be sure that you handle the error in web API properly, because especially transaction error is not displayed properly.
3- And, please remove t-sql from code :)
Select query doesn't block rows data from other transactions, two select in different transaction will be performed at the same time. You can try to set a session id on the row and then select it.
EDIT: hope this help, when update is executed it should block the row for others transactions
public async Task<TaskDetail> GetTask()
{
using (var db = new SqlConnection(""))
{
using (var tran = db.BeginTransaction())
{
try
{
var mySessionId = Guid.NewGuid();
var sql = $#"
UPDATE TaskStatus SET Status = #status, SessionId = #mySessionId WHERE TaskId in
(SELECT TOP 1
t.Id
FROM Task t
INNER JOIN TaskStatus ts ON t.Id = ts.TaskId AND ts.Status = #taskStatus ORDER BY NEWID());";
await db
.QuerySingleOrDefaultAsync<TaskDetail>(
sql,
param: new
{
taskStatus = TaskStatusEnum.Ready
status = TaskStatusEnum.InProgress,
mySessionId = mySessionId
},
transaction: tran
);
var sql = $#"
SELECT TOP 150 t.*
FROM Task t
INNER JOIN TaskStatus ts ON t.Id = ts.TaskId AND ts.Status = #taskStatus
WHERE ts.SessionId = #mySessionId;";
var chosen = await db
.QuerySingleOrDefaultAsync<TaskDetail>(
sql,
param: new
{
taskStatus = TaskStatusEnum.InProgress,
mySessionId = mySessionId
},
transaction: tran
);
if (chosen == null)
{
throw new InvalidOperationException();
}
var expiry = await db.ExecuteAsync("UPDATE TaskStatus SET Status = #status WHERE TaskId = #taskId", new {status = TaskStatusEnum.Done, taskId = chosen.TaskId}, tran);
tran.Commit();
return chosen;
}
catch
{
tran.Rollback();
throw;
}
}
}
}
I have standard lines of code, to fetch data with pagination. It used to work until a month ago, and then stopped. On running ExecuteNextAsync() it stops execution, and displays this following information in Output window:
DocDBTrace Information: 0 : DocumentClient with id 2 disposed.
DocDBTrace Information: 0 : DocumentClient with id 1 disposed.
Not Working Code:
var query =
client.CreateDocumentQuery(
UriFactory.CreateDocumentCollectionUri(databaseId, "TestCollection"), "select c.id from TestCollection c",
new FeedOptions
{
//MaxDegreeOfParallelism=-1,
MaxItemCount = maxItemCount,
PopulateQueryMetrics=true
//RequestContinuation = requestContinuation,
//EnableScanInQuery = true,
//EnableCrossPartitionQuery = true
});
var queryAll = query.AsDocumentQuery();
var results = new List<TDocument>();
while (queryAll.HasMoreResults)
{
try
{
var result = await queryAll.ExecuteNextAsync();
var queryMetrics = result.QueryMetrics;
if (result.ResponseContinuation != null) requestContinuation = result.ResponseContinuation;
//Do something here
}
catch (Exception ex)
{
}
}
For the same client object, Create/Update or fetching all items together is working. So JsonSerializer or DocumentClient object cannot be a problem.
Working code:
var query2 = client.CreateDocumentQuery(
UriFactory.CreateDocumentCollectionUri(databaseId, collectionName), "select * from TestCollection c",
new FeedOptions { MaxItemCount = -1 });
//.Where(l => l.Id == qId);
var testData2= query2.ToList();
This has stopped our services and their development. Any help is appreciated.
Your query is wrong.
UriFactory.CreateDocumentCollectionUri(databaseId, "TestCollection") will already let the SDK know what to query.
If you simply change
select c.id from TestCollection c
to
select c.id from c
It will work. Currently it is failing to resolve the c alias because you also have TestCollection there.
The only reason your other queries that use * are working is because you aren't using the c. there.
I want to invoke method durning mapping my domain class to DTO class but after many tries with LINQ to Entities or LINQ to objects i have failed and i'm getting weird different errors. Actulal error is just a "LINQ to Entities does not recognize the method 'System.String ResizeToLogoImage(System.String)' method, and this method cannot be translated into a store expression.".
Mapping method:
public async Task<SingleCategory> SingleCategoryMapping(EventerApiContext context, int id)
{
var category = await context.Category.Select(c => new SingleCategory
{
CategoryId = c.CategoryId,
CategoryName = c.CategoryName,
CityId = c.CityId,
Events = context.Event.ToList().Where(e=>e.CategoryId == id).Select(e=> new EventForSingleCategory
{
EventId = e.EventId,
EventName = e.EventName,
EventLogo = ImageProcessor.ResizeToLogoImage(e.EventDetail.EventImage.EventImageBase64)
}).ToList()
}).SingleOrDefaultAsync(c => c.CategoryId == id);
return category;
}
Method to be invoked.
public static string ResizeToLogoImage(string base64String)
{
if (base64String == null)
{
return "NULL";
}
var imageToResize = Base64ToImage(base64String);
var resizedImage = ScaleImage(imageToResize, 50, 50);
return ImageToBase64(resizedImage, imageToResize.RawFormat);
}
I know error is appearing during EventLogo property mapping but i have no more idea what to do.
Try to get the data first, before you do the Select statement. I suspect that it is trying to execute ResizeToLogoImage on the database :)
I have a little problem. I am encountering the following error each time I try update my entityset.
Unable to update the EntitySet 'ShoppingCart' because it has a
DefiningQuery and no InsertFunction element exists in the
ModificationFunctionMapping element to support the current
operation.
The code is: `
public void AddItem(string cartID, string productID, string quantity)
{
using (CommerceEntities db = new CommerceEntities())
{
try
{
var myItem = (from c in db.ShoppingCarts
where c.CartID == cartID &&
c.ProductID == productID
select c).FirstOrDefault();
if (myItem == null)
{
ShoppingCart cartadd = new ShoppingCart();
cartadd.CartID = cartID;
cartadd.Quantity = quantity;
cartadd.ProductID = productID;
cartadd.DateCreated = DateTime.Now;
db.ShoppingCarts.AddObject(cartadd);
}
else
{
myItem.Quantity += Convert.ToInt32(quantity);
}
db.SaveChanges();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Add Item to Cart - " +exp.Message);
}
}
}
`
Please help me. I can provide more information if required, I am new to this Entity Framework Model and following the tutorial on This page.
Update: I added primary keys and redesigned the whole database. Now the error changed to:
System.Data.UpdateException was unhandled by user code Message=An
error occurred while updating the entries. See the inner exception for
details.
This usually happens if entity set is mapped from database view, custom database query or if database table doesn't have primary key.