读取可能不存在的 Azure DocumentDB 文档
Read Azure DocumentDB document that might not exist
我可以像这样从 Azure DocumentDB 查询单个文档:
var response = await client.ReadDocumentAsync( documentUri );
如果文档不存在,这将抛出 DocumentClientException。在我的程序中,我遇到了文档可能存在也可能不存在的情况。有没有什么方法可以在不使用 try-catch 并且不对服务器进行两次往返的情况下查询文档,首先查询文档,然后检索文档是否存在?
您专门查询给定文档,ReadDocumentAsync
会在找不到特定文档时抛出 DocumentClientException
(在状态代码中返回 404)。这已记录在案 here。通过捕获异常(并看到它是 404),您不需要两次往返。
要避免处理此异常,您需要使用 CreateDocumentQuery()
进行查询而不是离散读取。然后,您将简单地获得一个可以枚举的结果集(即使该结果集为空)。例如:
var collLink = UriFactory.CreateDocumentCollectionUri(databaseId, collectionId);
var querySpec = new SqlQuerySpec { <querytext> };
var itr = client.CreateDocumentQuery(collLink, querySpec).AsDocumentQuery();
var response = await itr.ExecuteNextAsync<Document>();
foreach (var doc in response.AsEnumerable())
{
// ...
}
使用这种方法,您将得不到任何回复。在您的特定情况下,您将添加 WHERE
子句以通过其 ID 查询特定文档,您将获得零个结果或一个结果。
遗憾的是,没有其他方法,要么处理异常,要么进行两次调用,如果选择第二条路径,这是一种性能驱动的检查文档是否存在的方法:
public bool ExistsDocument(string id)
{
var client = new DocumentClient(DatabaseUri, DatabaseKey);
var collectionUri = UriFactory.CreateDocumentCollectionUri("dbName", "collectioName");
var query = client.CreateDocumentQuery<Microsoft.Azure.Documents.Document>(collectionUri, new FeedOptions() { MaxItemCount = 1 });
return query.Where(x => x.Id == id).Select(x=>x.Id).AsEnumerable().Any(); //using Linq
}
客户端应该在您所有的数据库访问方法之间共享,但我在那里创建它是为了有一个自动足够的示例。
new FeedOptions () {MaxItemCount = 1}
将确保查询针对 1 个结果进行优化(我们真的不需要更多)。
Select(x=>x.Id)
将确保没有其他数据被 return 编辑,如果您未指定它并且文档存在,它将查询并 return 所有信息。
使用 CosmosDB SDK 版本。 3这是可能的。您可以检查容器中是否存在某个项目并通过使用 Container.ReadItemStreamAsync<T>(string id, PartitionKey key)
并检查 response.StatusCode
:
来获取它
using var response = await container.ReadItemStreamAsync(id, new PartitionKey(key));
if (response.StatusCode == HttpStatusCode.NotFound)
{
return null;
}
if (!response.IsSuccessStatusCode)
{
throw new Exception(response.ErrorMessage);
}
using var streamReader = new StreamReader(response.Content);
var content = await streamReader.ReadToEndAsync();
var item = JsonConvert.DeserializeObject(content, stateType);
但是,这种方法有一个缺点。您需要手动反序列化项目。
我可以像这样从 Azure DocumentDB 查询单个文档:
var response = await client.ReadDocumentAsync( documentUri );
如果文档不存在,这将抛出 DocumentClientException。在我的程序中,我遇到了文档可能存在也可能不存在的情况。有没有什么方法可以在不使用 try-catch 并且不对服务器进行两次往返的情况下查询文档,首先查询文档,然后检索文档是否存在?
您专门查询给定文档,ReadDocumentAsync
会在找不到特定文档时抛出 DocumentClientException
(在状态代码中返回 404)。这已记录在案 here。通过捕获异常(并看到它是 404),您不需要两次往返。
要避免处理此异常,您需要使用 CreateDocumentQuery()
进行查询而不是离散读取。然后,您将简单地获得一个可以枚举的结果集(即使该结果集为空)。例如:
var collLink = UriFactory.CreateDocumentCollectionUri(databaseId, collectionId);
var querySpec = new SqlQuerySpec { <querytext> };
var itr = client.CreateDocumentQuery(collLink, querySpec).AsDocumentQuery();
var response = await itr.ExecuteNextAsync<Document>();
foreach (var doc in response.AsEnumerable())
{
// ...
}
使用这种方法,您将得不到任何回复。在您的特定情况下,您将添加 WHERE
子句以通过其 ID 查询特定文档,您将获得零个结果或一个结果。
遗憾的是,没有其他方法,要么处理异常,要么进行两次调用,如果选择第二条路径,这是一种性能驱动的检查文档是否存在的方法:
public bool ExistsDocument(string id)
{
var client = new DocumentClient(DatabaseUri, DatabaseKey);
var collectionUri = UriFactory.CreateDocumentCollectionUri("dbName", "collectioName");
var query = client.CreateDocumentQuery<Microsoft.Azure.Documents.Document>(collectionUri, new FeedOptions() { MaxItemCount = 1 });
return query.Where(x => x.Id == id).Select(x=>x.Id).AsEnumerable().Any(); //using Linq
}
客户端应该在您所有的数据库访问方法之间共享,但我在那里创建它是为了有一个自动足够的示例。
new FeedOptions () {MaxItemCount = 1}
将确保查询针对 1 个结果进行优化(我们真的不需要更多)。
Select(x=>x.Id)
将确保没有其他数据被 return 编辑,如果您未指定它并且文档存在,它将查询并 return 所有信息。
使用 CosmosDB SDK 版本。 3这是可能的。您可以检查容器中是否存在某个项目并通过使用 Container.ReadItemStreamAsync<T>(string id, PartitionKey key)
并检查 response.StatusCode
:
using var response = await container.ReadItemStreamAsync(id, new PartitionKey(key));
if (response.StatusCode == HttpStatusCode.NotFound)
{
return null;
}
if (!response.IsSuccessStatusCode)
{
throw new Exception(response.ErrorMessage);
}
using var streamReader = new StreamReader(response.Content);
var content = await streamReader.ReadToEndAsync();
var item = JsonConvert.DeserializeObject(content, stateType);
但是,这种方法有一个缺点。您需要手动反序列化项目。