В то время как базы данных без схемы, такие как DocumentDB, упрощают внесение изменений в вашу модель данных, вам все равно придется потратить некоторое время на обдумывание своих данных.
-
У вас есть много вариантов. Естественно, вы можете просто работать с графами объектов JSON или даже с необработанными строками текста JSON, но вы также можете использовать динамические объекты, которые позволяют связывать свойства во время выполнения, не определяя класс во время компиляции.
-
Вы также можете работать с реальными объектами C # или объектами, как они называются, которые могут быть классами вашего бизнес-домена.
У вас есть много вариантов. Естественно, вы можете просто работать с графами объектов JSON или даже с необработанными строками текста JSON, но вы также можете использовать динамические объекты, которые позволяют связывать свойства во время выполнения, не определяя класс во время компиляции.
Вы также можете работать с реальными объектами C # или объектами, как они называются, которые могут быть классами вашего бизнес-домена.
Отношения
Давайте посмотрим на иерархическую структуру документа. Он имеет несколько свойств верхнего уровня, таких как обязательный идентификатор, а также lastName и isRegistered, но также имеет вложенные свойства.
{ "id": "AndersenFamily", "lastName": "Andersen", "parents": [ { "firstName": "Thomas", "relationship": "father" }, { "firstName": "Mary Kay", "relationship": "mother" } ], "children": [ { "firstName": "Henriette Thaulow", "gender": "female", "grade": 5, "pets": [ { "givenName": "Fluffy", "type": "Rabbit" } ] } ], "location": { "state": "WA", "county": "King", "city": "Seattle"}, "isRegistered": true }
-
Например, свойство parent предоставляется в виде массива JSON, обозначенного квадратными скобками.
-
У нас также есть другой массив для дочерних элементов, хотя в этом примере есть только один дочерний массив. Вот как вы моделируете эквивалент отношения «один ко многим» в документе.
-
Вы просто используете массивы, где каждый элемент в массиве может быть простым значением или другим сложным объектом, даже другим массивом.
-
Таким образом, в одной семье может быть несколько родителей и несколько детей, и если вы посмотрите на дочерние объекты, у них есть свойство питомца, которое само по себе является вложенным массивом для отношений один-много между детьми и домашними животными.
-
Для свойства location мы объединяем три связанных свойства: штат, округ и город в объект.
-
Встраивание объекта таким способом, а не встраивание массива объектов, аналогично взаимно-однозначному отношению между двумя строками в отдельных таблицах в реляционной базе данных.
Например, свойство parent предоставляется в виде массива JSON, обозначенного квадратными скобками.
У нас также есть другой массив для дочерних элементов, хотя в этом примере есть только один дочерний массив. Вот как вы моделируете эквивалент отношения «один ко многим» в документе.
Вы просто используете массивы, где каждый элемент в массиве может быть простым значением или другим сложным объектом, даже другим массивом.
Таким образом, в одной семье может быть несколько родителей и несколько детей, и если вы посмотрите на дочерние объекты, у них есть свойство питомца, которое само по себе является вложенным массивом для отношений один-много между детьми и домашними животными.
Для свойства location мы объединяем три связанных свойства: штат, округ и город в объект.
Встраивание объекта таким способом, а не встраивание массива объектов, аналогично взаимно-однозначному отношению между двумя строками в отдельных таблицах в реляционной базе данных.
Встраивание данных
Когда вы начнете моделировать данные в хранилище документов, например DocumentDB, попытайтесь обработать свои сущности как автономные документы, представленные в JSON. При работе с реляционными базами данных мы всегда нормализуем данные.
-
Для нормализации ваших данных обычно требуется взять объект, например клиента, и разбить его на отдельные части данных, такие как контактные данные и адреса.
-
Чтобы прочитать клиента со всеми его контактными данными и адресами, вам нужно использовать JOINS для эффективной агрегации ваших данных во время выполнения.
Для нормализации ваших данных обычно требуется взять объект, например клиента, и разбить его на отдельные части данных, такие как контактные данные и адреса.
Чтобы прочитать клиента со всеми его контактными данными и адресами, вам нужно использовать JOINS для эффективной агрегации ваших данных во время выполнения.
Теперь давайте посмотрим, как мы будем моделировать те же данные, что и автономная сущность в базе данных документов.
{ "id": "1", "firstName": "Mark", "lastName": "Upston", "addresses": [ { "line1": "232 Main Street", "line2": "Unit 1", "city": "Brooklyn", "state": "NY", "zip": 11229 } ], "contactDetails": [ {"email": "[email protected]"}, {"phone": "+1 356 545-86455", "extension": 5555} ] }
Как видите, мы денормализовали запись клиента, где вся информация о клиенте встроена в один документ JSON.
В NoSQL у нас есть бесплатная схема, поэтому вы можете добавлять контактные данные и адреса в другом формате. В NoSQL вы можете извлечь запись клиента из базы данных за одну операцию чтения. Точно так же обновление записи также является единственной операцией записи.
Ниже приведены шаги по созданию документов с использованием .Net SDK.
Шаг 1 — Создание DocumentClient. Затем мы будем запрашивать базу данных myfirstdb, а также запрашивать коллекцию MyCollection, которую мы храним в этой коллекции частных переменных, чтобы она была доступна для всего класса.
private static async Task CreateDocumentClient() { // Create a new instance of the DocumentClient using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) { database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id = 'myfirstdb'").AsEnumerable().First(); collection = client.CreateDocumentCollectionQuery(database.CollectionsLink, "SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First(); await CreateDocuments(client); } }
Шаг 2 — Создайте несколько документов в задаче CreateDocuments.
private async static Task CreateDocuments(DocumentClient client) { Console.WriteLine(); Console.WriteLine("**** Create Documents ****"); Console.WriteLine(); dynamic document1Definition = new { name = "New Customer 1", address = new { addressType = "Main Office", addressLine1 = "123 Main Street", location = new { city = "Brooklyn", stateProvinceName = "New York" }, postalCode = "11229", countryRegionName = "United States" }, }; Document document1 = await CreateDocument(client, document1Definition); Console.WriteLine("Created document {0} from dynamic object", document1.Id); Console.WriteLine(); }
Первый документ будет создан из этого динамического объекта. Это может выглядеть как JSON, но, конечно, это не так. Это код C #, и мы создаем настоящий объект .NET, но нет определения класса. Вместо этого свойства выводятся из способа инициализации объекта. Вы также можете заметить, что мы не предоставили свойство Id для этого документа.
Шаг 3 — Теперь давайте посмотрим на CreateDocument, и он выглядит так же, как мы видели при создании баз данных и коллекций.
private async static Task<Document> CreateDocument(DocumentClient client, object documentObject) { var result = await client.CreateDocumentAsync(collection.SelfLink, documentObject); var document = result.Resource; Console.WriteLine("Created new document: {0}\r\n{1}", document.Id, document); return result; }
Шаг 4 — На этот раз мы вызываем CreateDocumentAsync, указывая SelfLink коллекции, в которую мы хотим добавить документ. Мы получаем ответ со свойством ресурса, которое в данном случае представляет новый документ с его сгенерированными системой свойствами.
В следующей задаче CreateDocuments мы создали три документа.
-
В первом документе объект Document — это определенный класс в SDK, который наследуется от ресурса и поэтому имеет все общие свойства ресурса, но также включает динамические свойства, которые определяют сам документ без схемы.
В первом документе объект Document — это определенный класс в SDK, который наследуется от ресурса и поэтому имеет все общие свойства ресурса, но также включает динамические свойства, которые определяют сам документ без схемы.
private async static Task CreateDocuments(DocumentClient client) { Console.WriteLine(); Console.WriteLine("**** Create Documents ****"); Console.WriteLine(); dynamic document1Definition = new { name = "New Customer 1", address = new { addressType = "Main Office", addressLine1 = "123 Main Street", location = new { city = "Brooklyn", stateProvinceName = "New York" }, postalCode = "11229", countryRegionName = "United States" }, }; Document document1 = await CreateDocument(client, document1Definition); Console.WriteLine("Created document {0} from dynamic object", document1.Id); Console.WriteLine(); var document2Definition = @" { ""name"": ""New Customer 2"", ""address"": { ""addressType"": ""Main Office"", ""addressLine1"": ""123 Main Street"", ""location"": { ""city"": ""Brooklyn"", ""stateProvinceName"": ""New York"" }, ""postalCode"": ""11229"", ""countryRegionName"": ""United States"" } }"; Document document2 = await CreateDocument(client, document2Definition); Console.WriteLine("Created document {0} from JSON string", document2.Id); Console.WriteLine(); var document3Definition = new Customer { Name = "New Customer 3", Address = new Address { AddressType = "Main Office", AddressLine1 = "123 Main Street", Location = new Location { City = "Brooklyn", StateProvinceName = "New York" }, PostalCode = "11229", CountryRegionName = "United States" }, }; Document document3 = await CreateDocument(client, document3Definition); Console.WriteLine("Created document {0} from typed object", document3.Id); Console.WriteLine(); }
-
Этот второй документ работает только с необработанной строкой JSON. Теперь мы вступаем в перегрузку для CreateDocument, который использует JavaScriptSerializer для десериализации строки в объект, который затем передается тому же методу CreateDocument, который мы использовали для создания первого документа.
-
В третьем документе мы использовали объект C # Customer, который определен в нашем приложении.
Этот второй документ работает только с необработанной строкой JSON. Теперь мы вступаем в перегрузку для CreateDocument, который использует JavaScriptSerializer для десериализации строки в объект, который затем передается тому же методу CreateDocument, который мы использовали для создания первого документа.
В третьем документе мы использовали объект C # Customer, который определен в нашем приложении.
Давайте посмотрим на этого клиента, у него есть свойство Id и address, где адрес — это вложенный объект со своими собственными свойствами, включая location, который является еще одним вложенным объектом.
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DocumentDBDemo { public class Customer { [JsonProperty(PropertyName = "id")] public string Id { get; set; } // Must be nullable, unless generating unique values for new customers on client [JsonProperty(PropertyName = "name")] public string Name { get; set; } [JsonProperty(PropertyName = "address")] public Address Address { get; set; } } public class Address { [JsonProperty(PropertyName = "addressType")] public string AddressType { get; set; } [JsonProperty(PropertyName = "addressLine1")] public string AddressLine1 { get; set; } [JsonProperty(PropertyName = "location")] public Location Location { get; set; } [JsonProperty(PropertyName = "postalCode")] public string PostalCode { get; set; } [JsonProperty(PropertyName = "countryRegionName")] public string CountryRegionName { get; set; } } public class Location { [JsonProperty(PropertyName = "city")] public string City { get; set; } [JsonProperty(PropertyName = "stateProvinceName")] public string StateProvinceName { get; set; } } }
У нас также есть атрибуты свойств JSON, потому что мы хотим поддерживать надлежащие соглашения по обе стороны границы.
Поэтому я просто создаю свой объект New Customer вместе с вложенными дочерними объектами и снова вызываю CreateDocument. Хотя у нашего объекта customer есть свойство Id, мы не указали его значение, поэтому DocumentDB сгенерировал его на основе GUID, как и в предыдущих двух документах.
Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод.