2015-08-19 2 views
3

Я следую this blog post из Microsoft, тестирующего DocumentDB.Запрос объектов POCO из DocumentDB

Я создал коллекцию и вставил 2 документа с помощью разных классов POCO в мое приложение. Он создал документы, но я не могу отфильтровать их обратно в соответствующие классы POCO. Я понял, что я запрашиваю всю коллекцию, поэтому она явно извлекает все документы, хранящиеся внутри этой коллекции.

Каков наилучший способ дифференцировать документы во время запроса, чтобы я мог запрашивать их отдельно по типу?

я могу добавить поле типа к документу и может получить от WHERE type="user", но я не уверен, что я не могу сделать SELECT * FROM users с users быть типом документа (если есть такая вещь в DocumentDB), а не сборник.

Вот как я создаю документы:

var user1= new User() 
    { 
     UserTypeId = 0, 
     UserName = "[email protected]", 
     Password = "12345", 
     PasswordSalt = "saltyPassword", 
     UserStatusId = 1, 
     ProfilePhotoKey = "KJSY" 
    }; 
    await DocumentDBRepository<User>.CreateItemAsync(user1); 

    var client = new Client() 
    { 
     ClientName = "client1", 
     Secret = "rxPBsIVYya2Jg2ZHPNG8gL0P36TnutiBehvEFgk938M=", 
     Title = "Administration Front End Application", 
     ApplicationTypeId = 0, 
     Active = false, 
     RefreshTokenLifeTime = 60, 
     AllowedOrigin = "http://localhost:8080", 
     AllowedRoles = "admin" 
    }; 
    await DocumentDBRepository<Client>.CreateItemAsync(client); 

Документ Db хранилище класса

public static class DocumentDBRepository<T> 
{ 
    //Use the Database if it exists, if not create a new Database 
    private static Database ReadOrCreateDatabase() 
    { 
     var db = Client.CreateDatabaseQuery() 
         .Where(d => d.Id == DatabaseId) 
         .AsEnumerable() 
         .FirstOrDefault(); 

     if (db == null) 
     { 
      db = Client.CreateDatabaseAsync(new Database { Id = DatabaseId }).Result; 
     } 

     return db; 
    } 

    //Use the DocumentCollection if it exists, if not create a new Collection 
    private static DocumentCollection ReadOrCreateCollection(string databaseLink) 
    { 
     var col = Client.CreateDocumentCollectionQuery(databaseLink) 
          .Where(c => c.Id == CollectionId) 
          .AsEnumerable() 
          .FirstOrDefault(); 

     if (col == null) 
     { 
      var collectionSpec = new DocumentCollection { Id = CollectionId }; 
      var requestOptions = new RequestOptions { OfferType = "S1" }; 

      col = Client.CreateDocumentCollectionAsync(databaseLink, collectionSpec, requestOptions).Result; 
     } 

     return col; 
    } 

    //Expose the "database" value from configuration as a property for internal use 
    private static string databaseId; 
    private static String DatabaseId 
    { 
     get 
     { 
      if (string.IsNullOrEmpty(databaseId)) 
      { 
       databaseId = ConfigurationManager.AppSettings["database"]; 
      } 

      return databaseId; 
     } 
    } 

    //Expose the "collection" value from configuration as a property for internal use 
    private static string collectionId; 
    private static String CollectionId 
    { 
     get 
     { 
      if (string.IsNullOrEmpty(collectionId)) 
      { 
       collectionId = ConfigurationManager.AppSettings["collection"]; 
      } 

      return collectionId; 
     } 
    } 

    //Use the ReadOrCreateDatabase function to get a reference to the database. 
    private static Database database; 
    private static Database Database 
    { 
     get 
     { 
      if (database == null) 
      { 
       database = ReadOrCreateDatabase(); 
      } 

      return database; 
     } 
    } 

    //Use the ReadOrCreateCollection function to get a reference to the collection. 
    private static DocumentCollection collection; 
    private static DocumentCollection Collection 
    { 
     get 
     { 
      if (collection == null) 
      { 
       collection = ReadOrCreateCollection(Database.SelfLink); 
      } 

      return collection; 
     } 
    } 

    //This property establishes a new connection to DocumentDB the first time it is used, 
    //and then reuses this instance for the duration of the application avoiding the 
    //overhead of instantiating a new instance of DocumentClient with each request 
    private static DocumentClient client; 
    private static DocumentClient Client 
    { 
     get 
     { 
      // change policy to ConnectionMode: Direct and ConnectionProtocol: TCP on publishing to AZURE 
      if (client == null) 
      { 
       string endpoint = ConfigurationManager.AppSettings["endpoint"]; 
       string authKey = ConfigurationManager.AppSettings["authKey"]; 
       Uri endpointUri = new Uri(endpoint); 
       client = new DocumentClient(endpointUri, authKey); 
      } 

      return client; 
     } 
    } 


    /* QUERY HELPERS */ 
    public static IEnumerable<T> GetAllItems() 
    { 
     return Client.CreateDocumentQuery<T>(Collection.DocumentsLink) 
      .AsEnumerable(); 
    } 
    public static IEnumerable<T> GetItems(Expression<Func<T, bool>> predicate) 
    { 
     return Client.CreateDocumentQuery<T>(Collection.DocumentsLink) 
      .Where(predicate) 
      .AsEnumerable(); 
    } 
    public static async Task<Document> CreateItemAsync(T item) 
    { 
     return await Client.CreateDocumentAsync(Collection.SelfLink, item); 
    } 
    public static T GetItem(Expression<Func<T, bool>> predicate) 
    { 
     return Client.CreateDocumentQuery<T>(Collection.DocumentsLink) 
        .Where(predicate) 
        .AsEnumerable() 
        .FirstOrDefault(); 
    } 

    public static async Task<Document> UpdateItemAsync(string id, T item) 
    { 
     Document doc = GetDocument(id); 
     return await Client.ReplaceDocumentAsync(doc.SelfLink, item); 
    } 

    private static Document GetDocument(string id) 
    { 
     return Client.CreateDocumentQuery(Collection.DocumentsLink) 
      .Where(d => d.Id == id) 
      .AsEnumerable() 
      .FirstOrDefault(); 
    } 
} 

Я пытаюсь получить:

var q = DocumentDBRepository<User>.GetAllItems().ToList(); 
    var t = DocumentDBRepository<Client>.GetAllItems().ToList(); 

д должен содержать только пользовательские документы тех, были созданы

await DocumentDBRepository<User>.CreateItemAsync(user1); 

и т должен содержать только документы клиента те были созданы

await DocumentDBRepository<Client>.CreateItemAsync(client1); 

ответ

2

Поскольку DocumentDB не имеет какой-либо встроенные type метаданных для каждого документа, вам необходимо добавить один (например, type, которое вы предложили, или любое другое отличительное свойство) при хранении разнородных документов в одном сборнике и использовать его в своем предложении WHERE. То, что вы называете этим свойством, и какие значения вы храните в нем, не имеют ничего общего с вашим именем коллекции.

Относительно вашего конкретного примера SELECT * from users WHERE type='user' будет работать, но SELECT * from users вернет все документы независимо от их типа.

По умолчанию все свойства индексируются, включая недавно сформированное свойство type, которое позволяет эффективно выполнять фильтрацию WHERE-предложений без необходимости сканирования коллекции.

+0

Я нашел это сообщение http://feedback.azure.com/forums/263030-documentdb/suggestions/6345705-3-collections-per-capacity-unit-is-way-too-small, как только я напишу вопрос. Команда Azure заявила, что они работают над группировкой документов внутри коллекции. На данный момент я буду придерживаться ручного дифференциации. :) – Azadrum

+0

И теперь я собираюсь хранить свои умные данные (чтобы сотрудники, работающие в этом отделе, или дети этого семейства) в documentDB и подробную информацию об объектах в хранилище таблиц. У вас есть мнение о том, как использовать DocumentDB с табличным хранилищем? – Azadrum

+0

@ Azadrum - тема из 3-сборных шкал устарела, так как каждая коллекция теперь является собственной шкалой. Что касается хранения данных за пределами DocumentDB: это должен быть отдельный вопрос, но ... вопросы, основанные на мнениях, обычно закрываются довольно быстро. Возможно, вы зададите объективный, конкретный вопрос, который вы можете задать в этой области? –

0

Regaring как дифференцировать типы документов в коллекции ...

Я начал с использованием атрибута Type, который просто взял имя iternal типа (поглотитель в базовом классе «Entity»)

Мои ожидалось, что мы будем использовать атрибут Type при запросе.

Однако мы быстро перешли к использованию значения типа вместо этого в качестве суффикса ключа раздела для каждого типа сущности («pkey» снова унаследован от Entity - поскольку мы находимся в состоянии «$», сохраняя все в одной коллекции, использовать один раздел имя ключа атрибута для всех типов документов)

Если имя типа является «Вещь» и есть один только тогда «идентификатор» является «Вещь» и PKey является «-identifier- | Thing»

Если -identifier - идентифицирует группу, тогда несколько записей будут иметь уникальные значения для «id», а запросы диапазона легко просто запросить на pkey и итерации.

Имя типа должно быть суффикс PKey, чтобы убедиться, что вы не уменьшают читать и писать распределение

идентификатор и PKEY также работают хорошо, как уникальный индекс - приветствуется, когда вы оказываетесь отсутствует реляционную SQL: -)

Что касается POCO - я всерьез подумываю о том, чтобы отказаться от прямых операций POCO, так как у нас было так много проблем с серией сериализации и sql-запросов на camelcase json. Мы закончили тем, что не смогли доверять глобальным настройкам верблюжьей линейки, вместо этого исчерпывающе установили имя json во всех полях.

Что я думаю о переходе к использованию внутреннего POCO, который сохраняется в документе и из документа. Получатели и сеттеры POCO ссылаются на экземпляр документа через getAttributeValue() setAttributeValue(). Затем мы можем поменять наш слой устойчивости на что-то еще через DI

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

Разделение нашего POCO от стойкости также желательно.

Только некоторые мысли для вас.

Смежные вопросы