C# 读取可能不存在的Azure DocumentDB文档

C# 读取可能不存在的Azure DocumentDB文档,c#,.net,azure,azure-cosmosdb,C#,.net,Azure,Azure Cosmosdb,我可以从Azure DocumentDB查询单个文档,如下所示: var response = await client.ReadDocumentAsync( documentUri ); 如果文档不存在,这将抛出DocumentClientException。在我的程序中,我的文档可能存在,也可能不存在。有没有办法不使用try-catch和不到服务器执行两次往返(第一次查询文档,第二次检索文档(如果文档存在))来查询文档,而readdocumentsync将在找不到特定文档时抛出该Docum

我可以从Azure DocumentDB查询单个文档,如下所示:

var response = await client.ReadDocumentAsync( documentUri );

如果文档不存在,这将抛出DocumentClientException。在我的程序中,我的文档可能存在,也可能不存在。有没有办法不使用try-catch和不到服务器执行两次往返(第一次查询文档,第二次检索文档(如果文档存在))来查询文档,而
readdocumentsync
将在找不到特定文档时抛出该
DocumentClientException
(在状态代码中返回404)。这是有案可查的。通过捕获异常(并看到它是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())
{
    // ...
}
var collink=UriFactory.CreateDocumentCollectionUri(数据库ID,collectionId);
var querySpec=新的SqlQuerySpec{};
var itr=client.CreateDocumentQuery(collLink,querySpec).AsDocumentQuery();
var response=wait itr.ExecuteNextAsync();
foreach(响应中的var doc.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
}
public bool ExistsDocument(字符串id)
{
var client=newdocumentclient(DatabaseUri,DatabaseKey);
var collectionUri=UriFactory.CreateDocumentCollectionUri(“dbName”、“CollectionName”);
var query=client.CreateDocumentQuery(collectionUri,new FeedOptions(){MaxItemCount=1});
返回query.Where(x=>x.Id==Id)。选择(x=>x.Id)。AsEnumerable().Any();//使用Linq
}
客户机应该在所有DB访问方法中共享,但我在那里创建它是为了有一个auto-Sufficient示例

newfeedoptions(){MaxItemCount=1}
将确保查询将针对1个结果进行优化(我们实际上不需要更多)


Select(x=>x.Id)
将确保不返回任何其他数据,如果您未指定该数据且文档存在,它将查询并返回其所有信息。

使用CosmosDB SDK版本。这是可能的。您可以使用
container.ReadItemStreamAsync(string id,PartitionKey)
检查容器中是否存在项目,并通过检查
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);

然而,这种方法有一个缺点。您需要手动反序列化该项。

您可能无论如何都希望处理异常,因此这似乎比飞行前检查是否存在要好得多,IMHO。处理异常是更好的方法,在大多数情况下,通过Id进行查询所使用的RU比通过Id只找到一个结果的查询要少。奇怪的是,我们不得不求助于异常。通过异常进行通信通常会变得昂贵,因为异常往往很严重,而且通常是不允许的。在这种情况下,因为这是通过TCP进行的,所以服务器需要返回代码,在这种情况下,它是404。所以这有点像是一种必要的邪恶。我喜欢使用查询来查看是否有任何结果。这不会导致例外情况。使用try-catch时,代码看起来也很奇怪。