Как сделать запрос для определенного типа, а затем получить базовый документ - PullRequest
0 голосов
/ 25 августа 2018

Я пытаюсь выполнить запрос по определенному типу документа

MyType foo = client.CreateDocumentQuery<MyType>(documentCollectionUri)
   .ToList()
   .FirstOrDefault(d => d.SomeProperty == someProperty);

затем замените документ другим. Похоже, единственными доступными методами являются

public Task<ResourceResponse<Document>> ReplaceDocumentAsync(Uri documentUri, object document, RequestOptions options = null);

public Task<ResourceResponse<Document>> ReplaceDocumentAsync(Document document, RequestOptions options = null);

public Task<ResourceResponse<Document>> ReplaceDocumentAsync(string documentLink, object document, RequestOptions options = null);

все из которых требуют Document или id.

Итак, как мне получить эти значения из foo? Не возможно?

Ответы [ 2 ]

0 голосов
/ 26 августа 2018

Во-первых, что-то не совсем понятно по тому, как вы выражаете свой вопрос.

MyType foo = client.CreateDocumentQuery<MyType>(documentCollectionUri)
   .ToList()
   .FirstOrDefault(d => d.SomeProperty == someProperty);

Если вы храните несколько разных типов объектов в одном и том же вопросе, тогда с помощью параметра T MyType не гарантирует, что результаты, которые вы получите, будут только MyType результатами, а все, что соответствует выражению, будет отображено и возвращено как MyType.В CosmosDB SDK нет другой фильтрации, которая гарантирует, что запрос будет выполняться только для объектов этого типа, потому что CosmosDB не имеет контекста этого.

Единственный надежный способ сделать это, используя метод ReplaceDocumentAsyncзаключается в том, чтобы (как сказал Alex AIT) добавить свойство Id с атрибутом [JsonProperty("id")] к вашему объекту.Учитывая, что это DTO, а не объект Domain, это свойство должно быть там, и оно действительно поможет с другими функциями, такими как удаление, и т. Д.

Я очень рекомендую взглянуть на Cosmonaut которая представляет собой CosmosDB ORM, которая также обеспечивает совместное использование коллекций на основе типов и те же запросы и обновления, которые вы пытаетесь достичь, не связываясь с какой-либо подобной логикой.

Отказ от ответственности: я являюсь создателем Cosmonaut

В примечании не следует использовать ToList() для IQueryable, созданного с использованием CreateDocumentQuery, но вместо этого использовать метод .AsDocumentQuery() для него, а затем использовать комбинацию while(query.HasMoreResults), а затем query.ExecuteNextAsync() метод правильного использования функциональности разбитого на страницы CosmosDB.

0 голосов
/ 26 августа 2018

Во-первых, вы должны сделать ваш запрос следующим образом:

List<MyType> foo = client.CreateDocumentQuery<MyType>(documentCollectionUri)
  .Where(d => d.SomeProperty == someProperty);
  .ToList();

В противном случае вы получите все документы из базы данных еще до того, как отфильтруете свою собственность.

Для вашего актуального вопроса у вас есть два варианта:

1) Сделайте идентификационную часть вашего документа

CosmosDB автоматически установит Id при сохранении и десериализует его в поле при получении документа. Затем вы можете использовать идентификатор для операции замены.

class MyType{

 [Newtonsoft.Json.JsonProperty(PropertyName="id")]      
public string Id {get; set;}
}
// Get documentUri by:
UriFactory.CreateDocumentUri(string databaseId, string collectionId, string documentId)
public Task<ResourceResponse<Document>> ReplaceDocumentAsync(Uri documentUri, object document, RequestOptions options = null);

2) Отделить определение запроса от выполнения запроса

Вы можете использовать различные типы для определения запроса и десериализации ответа. Таким образом, вы можете запросить MyType и десериализовать ответ как Document.

var query = client.CreateDocumentQuery<MyType>(documentCollectionUri)
  .Where(d => d.SomeProperty == someProperty)
  .AsDocumentQuery();

var response = await query.ExecuteNextAsync<Document>(cancellationToken).ConfigureAwait(false);
var document = response.FirstOrDefault();
...