DocumentDB - การสร้างแบบจำลองข้อมูล

แม้ว่าฐานข้อมูลที่ไม่มีสคีมาเช่น DocumentDB จะทำให้การเปลี่ยนแปลงโมเดลข้อมูลของคุณเป็นเรื่องง่ายมาก แต่คุณควรใช้เวลาคิดเกี่ยวกับข้อมูลของคุณ

  • คุณมีตัวเลือกมากมาย โดยปกติคุณสามารถทำงานกราฟออบเจ็กต์ 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 ตามที่แสดงโดยวงเล็บเหลี่ยม

  • นอกจากนี้เรายังมีอาร์เรย์อื่นสำหรับเด็กแม้ว่าจะมีลูกเดียวในอาร์เรย์ในตัวอย่างนี้ นี่คือวิธีที่คุณสร้างโมเดลให้เทียบเท่ากับความสัมพันธ์แบบหนึ่งต่อกลุ่มภายในเอกสาร

  • คุณเพียงแค่ใช้อาร์เรย์โดยที่แต่ละองค์ประกอบในอาร์เรย์อาจเป็นค่าธรรมดาหรือวัตถุที่ซับซ้อนอื่นแม้แต่อาร์เรย์อื่น

  • ดังนั้นครอบครัวหนึ่งสามารถมีพ่อแม่หลายคนและมีลูกได้หลายคนและหากคุณมองไปที่วัตถุของเด็กพวกเขาจะมีทรัพย์สินของสัตว์เลี้ยงซึ่งเป็นอาร์เรย์ที่ซ้อนกันสำหรับความสัมพันธ์ระหว่างเด็กและสัตว์เลี้ยง

  • สำหรับคุณสมบัติตำแหน่งเรากำลังรวมคุณสมบัติที่เกี่ยวข้องสามอย่างรัฐเขตและเมืองไว้ในวัตถุ

  • การฝังวัตถุด้วยวิธีนี้แทนที่จะฝังอาร์เรย์ของวัตถุคล้ายกับการมีความสัมพันธ์แบบหนึ่งต่อหนึ่งระหว่างสองแถวในตารางแยกกันในฐานข้อมูลเชิงสัมพันธ์

การฝังข้อมูล

เมื่อคุณเริ่มสร้างโมเดลข้อมูลในที่เก็บเอกสารเช่น DocumentDB ให้พยายามปฏิบัติต่อเอนทิตีของคุณเป็นเอกสารที่มีอยู่ในตัวซึ่งแสดงใน JSON เมื่อทำงานกับฐานข้อมูลเชิงสัมพันธ์เราจะทำให้ข้อมูลเป็นมาตรฐานเสมอ

  • โดยทั่วไปการทำให้ข้อมูลของคุณเป็นปกติจะเกี่ยวข้องกับการพิจารณาเอนทิตีเช่นลูกค้าและแยกย่อยออกเป็นส่วนข้อมูลที่รอบคอบเช่นรายละเอียดการติดต่อและที่อยู่

  • ในการอ่านลูกค้าพร้อมรายละเอียดการติดต่อและที่อยู่ทั้งหมดคุณต้องใช้ 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

Step 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); 
   }

}

Step 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 สำหรับเอกสารนี้

Step 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; 
}

Step 4- คราวนี้เราเรียก CreateDocumentAsync ระบุ SelfLink ของคอลเล็กชันที่เราต้องการเพิ่มเอกสาร เราได้รับการตอบกลับพร้อมคุณสมบัติทรัพยากรที่ในกรณีนี้แสดงถึงเอกสารใหม่ที่มีคุณสมบัติที่ระบบสร้างขึ้น

ในงาน CreateDocuments ต่อไปนี้เราได้สร้างเอกสารสามชุด

  • ในเอกสารแรกอ็อบเจ็กต์ 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 # ลูกค้าซึ่งกำหนดไว้ในใบสมัครของเรา

ลองมาดูที่ลูกค้ารายนี้มีคุณสมบัติ Id และ address โดยที่อยู่เป็นอ็อบเจ็กต์ที่ซ้อนกันซึ่งมีคุณสมบัติของตัวเองรวมถึงตำแหน่งซึ่งเป็นอีกอ็อบเจกต์ที่ซ้อนกัน

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 อีกครั้ง แม้ว่าออบเจ็กต์ลูกค้าของเราจะมีคุณสมบัติ Id แต่เราก็ไม่ได้ให้ค่าสำหรับมันดังนั้น DocumentDB จึงสร้างขึ้นมาตาม GUID เช่นเดียวกับที่ทำกับเอกสารสองชุดก่อนหน้า

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้

**** Create Documents ****  
Created new document: 575882f0-236c-4c3d-81b9-d27780206b2c 
{ 
  "name": "New Customer 1", 
  "address": { 
    "addressType": "Main Office", 
    "addressLine1": "123 Main Street", 
    "location": { 
      "city": "Brooklyn", 
      "stateProvinceName": "New York" 
    }, 
    "postalCode": "11229", 
    "countryRegionName": "United States" 
  }, 
  "id": "575882f0-236c-4c3d-81b9-d27780206b2c", 
  "_rid": "kV5oANVXnwDGPgAAAAAAAA==", 
  "_ts": 1450037545, 
  "_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDGPgAAAAAAAA==/", 
  "_etag": "\"00006fce-0000-0000-0000-566dd1290000\"", 
  "_attachments": "attachments/" 
} 
Created document 575882f0-236c-4c3d-81b9-d27780206b2c from dynamic object  
Created new document: 8d7ad239-2148-4fab-901b-17a85d331056 
{ 
  "name": "New Customer 2", 
  "address": {
    "addressType": "Main Office", 
    "addressLine1": "123 Main Street", 
    "location": { 
      "city": "Brooklyn", 
      "stateProvinceName": "New York" 
    }, 
    "postalCode": "11229", 
    "countryRegionName": "United States" 
  }, 
  "id": "8d7ad239-2148-4fab-901b-17a85d331056", 
  "_rid": "kV5oANVXnwDHPgAAAAAAAA==", 
  "_ts": 1450037545, 
  "_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDHPgAAAAAAAA==/", 
  "_etag": "\"000070ce-0000-0000-0000-566dd1290000\"", 
  "_attachments": "attachments/" 
} 
Created document 8d7ad239-2148-4fab-901b-17a85d331056 from JSON string  
Created new document: 49f399a8-80c9-4844-ac28-cd1dee689968 
{ 
  "id": "49f399a8-80c9-4844-ac28-cd1dee689968", 
  "name": "New Customer 3", 
  "address": { 
    "addressType": "Main Office", 
    "addressLine1": "123 Main Street", 
    "location": { 
      "city": "Brooklyn", 
      "stateProvinceName": "New York" 
    }, 
    "postalCode": "11229", 
    "countryRegionName": "United States" 
  }, 
  "_rid": "kV5oANVXnwDIPgAAAAAAAA==", 
  "_ts": 1450037546, 
  "_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDIPgAAAAAAAA==/", 
  "_etag": "\"000071ce-0000-0000-0000-566dd12a0000\"", 
  "_attachments": "attachments/" 
}
Created document 49f399a8-80c9-4844-ac28-cd1dee689968 from typed object