Data Modeling Nedir? Requirement'tan Conceptual, Logical ve Physical Modele
Data modeling, hangi veriyi hangi kurallarla saklayacağına kod yazmadan önce karar vermektir; şema yanlışsa hiçbir index onu doğru yapmaz. Conceptual, logical ve physical seviyeleri, requirement cümlelerinden entity, ilişki ve kural çıkarmayı, access pattern listesini ve ekran class'ından türetilen EF Core şemasının neden tek bir JSON'lu tabloya dönüştüğünü Bookstore üzerinden gösteriyoruz.
Sürüm notu: Bu yazıdaki SQL (Structured Query Language) örnekleri SQL Server 2025 (17.0, Cumulative Update 10) üzerinde, C# örneği .NET 10 ve Entity Framework Core (EF Core) 10.0.15 ile çalıştırılmıştır.
Önce Tahmin Et: Bu Şemayı Kim Tasarladı?
Küçük bir kitapçı, siparişlerini aylardır bir Excel dosyasında tutuyor. Yeni bir web uygulaması yazılacak ve ekipteki geliştirici sipariş ekranına bakıp şu class'ı yazıyor. Ekranda ne varsa class'ta da o var: müşterinin adı, e-postası, şehri, sepetteki kitapların adları, fiyatları ve toplam.
public class Order
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public string CustomerName { get; set; } = "";
public string CustomerEmail { get; set; } = "";
public string City { get; set; } = "";
public List<string> BookTitles { get; set; } = [];
public List<decimal> Prices { get; set; } = [];
public decimal Total { get; set; }
}
public class ScreenContext : DbContext
{
public DbSet<Order> Orders => Set<Order>();
protected override void OnConfiguring(DbContextOptionsBuilder options) =>
options.UseSqlServer(Environment.GetEnvironmentVariable("BOOKSTORE_DB")
?? "Server=localhost;Database=Bookstore;Trusted_Connection=True;TrustServerCertificate=True")
.LogTo(Console.WriteLine, [SqlServerEventId.DecimalTypeDefaultWarning]);
}
Migration'a hiç bakmadan tahmin et: EF Core bu class için nasıl bir tablo üretir? BookTitles listesi nereye gider? Bir kitabın adı düzeltilince kaç satır güncellenir? Aynı müşteri ikinci kez sipariş verince adı kaç yerde yazılı olur?
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using var db = new ScreenContext();
Console.WriteLine(db.Database.GenerateCreateScript());
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
db.Orders.Add(new Order
{
OrderDate = new DateTime(2026, 3, 2),
CustomerName = "Ada Lovelace",
CustomerEmail = "ada@example.com",
City = "Istanbul",
BookTitles = ["Dune", "Good Omens"],
Prices = [390.50m, 340.90m],
Total = 731.40m
});
db.SaveChanges();
var titles = db.Database
.SqlQueryRaw<string>("SELECT BookTitles AS Value FROM Orders")
.ToList();
Console.WriteLine($"Stored BookTitles: {titles[0]}");
warn: 14.11.2026 00:15:49.024 SqlServerEventId.DecimalTypeDefaultWarning[30000] (Microsoft.EntityFrameworkCore.Model.Validation)
No store type was specified for the decimal property 'Total' on entity type 'Order'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'.
CREATE TABLE [Orders] (
[Id] int NOT NULL IDENTITY,
[OrderDate] datetime2 NOT NULL,
[CustomerName] nvarchar(max) NOT NULL,
[CustomerEmail] nvarchar(max) NOT NULL,
[City] nvarchar(max) NOT NULL,
[BookTitles] nvarchar(max) NOT NULL,
[Prices] nvarchar(max) NOT NULL,
[Total] decimal(18,2) NOT NULL,
CONSTRAINT [PK_Orders] PRIMARY KEY ([Id])
);
Stored BookTitles: ["Dune","Good Omens"]
Tek bir tablo çıktı. Her metin nvarchar(max), kitap adları JSON (JavaScript Object Notation) array'i olarak tek kolonda, fiyatlar başka bir JSON array'inde ve ikisinin aynı sırada kalacağına dair hiçbir garanti yok. EF Core 8'den beri gelen primitive collection desteği (EF Core serisinin "EF Core 8 Yenilikleri" yazısı) burada işini kusursuz yaptı: class'ta liste vardı, veritabanında da liste var. Sorun EF Core'da değil. Sorun, kimsenin "Bu veritabanında hangi şeyleri, hangi kurallarla saklıyoruz?" sorusunu sormamış olması. Kitap diye bir tablo yok, yazar yok, müşteri yok. Ada'nın ikinci siparişinde e-postası yine yazılacak, kitap adındaki bir yazım hatası her siparişte ayrı ayrı düzeltilecek. Uyarı satırı da önemli bir şey söylüyor: Total için precision'ı kimse seçmedi, framework varsayılanı seçti.
Bu seri, tam olarak bu soruyu sormayı öğretiyor. Seri boyunca tek bir düz "sipariş Excel'i"ni alıp adım adım Bookstore şemasına dönüştüreceğiz. Bu ilk yazıda data modeling'in ne olduğunu, modelin üç seviyesini ve requirement cümlelerinden modelin nasıl çıkarıldığını görüyoruz.
Data Modeling Nedir ve Neden Önce Gelir?
Data modeling, bir sistemin hangi veriyi tuttuğunu, bu verinin parçalarının birbiriyle nasıl ilişkili olduğunu ve hangi kurallara uymak zorunda olduğunu, kod yazmadan önce açıkça kararlaştırma işidir. Çıktısı bir model: varlıklar, özellikleri, aralarındaki ilişkiler ve kısıtlar. Bu model bir diyagramda, bir dokümanda ya da doğrudan DDL (Data Definition Language) script'inde yaşayabilir; önemli olan kararların bilinçli verilmiş olması.
İlişkisel veritabanlarının teorik temeli E. F. Codd'un 1970'te CACM (Communications of the Association for Computing Machinery) dergisinde yayımlanan "A Relational Model of Data for Large Shared Data Banks" makalesine dayanır. Codd'un derdi, veriyi kullanan programların verinin diskte nasıl durduğundan etkilenmemesiydi. 1976'da Peter Chen ER (Entity-Relationship) modelini yayımladı ve iş dünyasının "şeyler ve aralarındaki ilişkiler" diliyle tabloları birbirine bağlayan bir çizim dili önerdi. Bugün kullandığımız data modeling pratiği bu ikisinin üstüne kurulu.
Model neden önce gelir? Çünkü şemanın hatası, kodun hatasından farklı yaşlanır. Yanlış yazılmış bir method'u bir commit'te düzeltirsin. Yanlış kurulmuş bir tabloyu düzeltmek için ise içindeki milyonlarca satırı taşıman, o tabloyu okuyan her sorguyu, raporu ve entegrasyonu değiştirmen gerekir. Index, cache ya da daha büyük bir sunucu yanlış modeli hızlandırabilir ama doğru yapamaz: kitap adları JSON array'inde duruyorsa "Dune'u en çok kim aldı?" sorusu her seferinde bütün siparişleri açıp içine bakmak demektir ve hiçbir index o sorunun anlamını değiştirmez.
Modelin Üç Seviyesi: Conceptual, Logical, Physical
Data modeling pratiğinde model genellikle üç seviyede düşünülür. Her seviye bir öncekine yeni kararlar ekler ve her seviyenin okuru farklıdır.

| Seviye | Ne söyler | Ne söylemez | Bookstore örneği |
|---|---|---|---|
| Conceptual | İş kavramları ve aralarındaki ilişkiler | Attribute listesi, key, veri tipi | Müşteri sipariş verir, sipariş kitap içerir, kitabın yazarları olur |
| Logical | Entity'ler, attribute'lar, key'ler, cardinality, normal form | Hangi veritabanı ürünü, hangi tip, hangi index | Book(book_id, isbn, title, list_price), M-N ilişki için BookAuthor |
| Physical | Tablo, kolon tipi, constraint, index, ürüne özgü özellik | İşin neden böyle olduğu | CHAR(13) isbn, DECIMAL(10,2) fiyat, UQ_books_isbn |
Conceptual model iş birimiyle konuşmak içindir. "Bir sipariş birden çok kitap içerir mi?", "Kitabın birden çok yazarı olabilir mi?" gibi sorular bu seviyede sorulur ve cevaplanır. Burada kolon yoktur; olsa bile iş birimi onu okumaz.
Logical model, kavramları ilişkisel modelin diline çevirir: her entity'nin attribute'ları, her ilişkinin cardinality'si, her tablonun key'i ve dependency'leri. Hâlâ ürün bağımsızdır; aynı logical model SQL Server'da da PostgreSQL'de de kurulabilir. Normalizasyon bu seviyenin işidir ve serinin ikinci bloğunu kaplar.
Physical model, logical modelin belirli bir DBMS (Database Management System) üzerindeki karşılığıdır: NVARCHAR mı VARCHAR mı, INT mi BIGINT mi, hangi constraint, hangi index, hangi collation. Bu seriye SQL Server 2025 üzerinden bakıyoruz; PostgreSQL 18'de farklı davranan yerleri not olarak düşeceğiz.
Bir not: Veritabanı literatüründe "üç seviye" deyince akla ilk ANSI'nin (American National Standards Institute) SPARC (Standards Planning and Requirements Committee) çalışma grubunun 1975 ara raporundaki external, conceptual ve internal şema ayrımı gelir. O ayrım bir DBMS'in mimarisini anlatır; buradaki conceptual/logical/physical ise tasarım sürecinin adımlarıdır. İsimler benzese de aynı şey değiller.
Requirement Cümlelerinden Model Çıkarmak
Model boş bir sayfada başlamaz, requirement cümlelerinden başlar. Kitapçının sahibiyle yaptığımız toplantıdan şu notlar çıktı:
- R1. Bir kitabın birden çok yazarı olabilir; kapakta yazarların sırası önemlidir.
- R2. Her kitabın bir ISBN'i (International Standard Book Number) vardır ve iki kitap aynı ISBN'i taşıyamaz.
- R3. Müşteri bir siparişte birden çok kitap alabilir, aynı kitaptan birden fazla adet de alabilir.
- R4. Sipariş anındaki fiyat sonradan değişmez; katalog fiyatı değişse bile eski sipariş aynı tutarı gösterir.
- R5. Müşteri sisteme e-posta adresiyle girer ve e-postasını değiştirebilir.
- R6. Sipariş iptal edilebilir ama silinmez; muhasebe geçmişi görmek zorundadır.
- R7. Her kitap bir kategoriye bağlıdır, kategoriler iç içedir (Bilim Kurgu, Kurgu'nun altındadır).
Bu cümleleri okurken üç şeyi ayıklıyoruz. İsimler entity adayıdır: kitap, yazar, müşteri, sipariş, kategori. Fiiller ilişki adayıdır: müşteri sipariş verir, sipariş kitap içerir, yazar kitap yazar. Sayılar, "birden çok", "en fazla", "her" gibi niceleyiciler ve "değişmez", "silinmez" gibi kelimeler ise kuraldır; cardinality'ye ve constraint'e dönüşür.
R3'te gizli bir entity var. "Bir siparişte birden çok kitap, aynı kitaptan birden fazla adet" cümlesi bir isim içermiyor ama "adet" bir şeyin attribute'u olmak zorunda. Adet siparişin attribute'u değil, çünkü siparişte birden çok kitap var. Kitabın da değil, çünkü aynı kitap farklı siparişlerde farklı adetle satılıyor. Adet, "bu siparişteki bu kitap" bilgisinin attribute'u. Yani sipariş kalemi (order item) diye ayrı bir kavram var ve iş birimi ona hiç isim vermemiş. Requirement'ta görünmeyen entity'leri bulmak, modelin en değerli kısmıdır.
R4 de aynı kalemin içinde başka bir şey söylüyor: sipariş anındaki fiyat kitabın fiyatı değil, kalemin fiyatı. Katalogdaki list_price ile kalemdeki unit_price iki farklı olgu. Biri "bu kitap bugün kaça satılıyor", diğeri "bu siparişte bu kitap kaça satıldı". Bunu bir tekrar sanıp tek kolona indirmek serinin ilerisinde göreceğimiz klasik hatalardan biri.
R5 bir key kararını önceden haber veriyor: e-posta değişebiliyorsa müşterinin kimliği e-posta olamaz. R1'deki "sıra önemli" ise ilişkinin kendisinin de bir attribute'u olduğunu söylüyor; yazar sırası ne kitabın ne yazarın, "bu kitaptaki bu yazar" ilişkisinin bilgisi. R6, silme davranışını modelin bir parçası yapıyor: sipariş için DELETE değil, bir status geçişi tasarlayacağız. R2 ise masum görünüyor ama serinin 4. yazısında ISBN'i olmayan kitaplarla karşılaşınca tekrar konuşacağız.
Access Pattern'leri Modelin Girdisi Olarak Not Etmek
Requirement'lar verinin ne olduğunu söyler; access pattern'ler (erişim şekilleri) ise ona nasıl dokunulacağını. Logical model access pattern'e göre bükülmez, ama physical karar verirken bu liste elinde olmazsa index'i, denormalization'ı ve hatta tablo sınırlarını tahminle seçersin. Kitapçı için ilk liste şöyle:
- Kitap detay sayfası: id ya da ISBN ile tek kitap, yazarları, kategorisi, ortalama puanı. En sık okunan sayfa.
- Kategori sayfası: bir kategorideki ve alt kategorilerindeki aktif kitaplar, sayfalı ve sıralı.
- Sipariş oluşturma: sipariş, kalemleri ve stok düşümü tek transaction'da. En kritik yazma işi.
- Müşterinin sipariş geçmişi: bir müşterinin siparişleri, yeniden eskiye.
- Aylık satış raporu: kategori ve ay bazında ciro. Seyrek ama ağır bir okuma.
Bu listenin her satırının yanına kabaca bir sıklık ve büyüklük yazmak işe yarar: "detay sayfası saniyede onlarca kez, sipariş dakikada birkaç kez, rapor ayda bir". Bu sayılar System Design serisinin "Back-of-the-Envelope Estimation" yazısındaki hesapla çıkarılır. Rapor satırı ayrıca bir uyarı taşıyor: ağır analitik okumalar, sipariş yazan OLTP (Online Transaction Processing) şemasında yaşamak zorunda değil. Bu konuya serinin 10. yazısında, dimensional model ve star schema ile döneceğiz.
Logical'dan Physical'a: Bir Kararın Yolculuğu
R1, R2 ve R4'ün physical karşılığını SQL Server'da kuralım. İsimler SQL Temelleri serisindeki Bookstore şemasıyla aynı: snake_case, çoğul tablo adları, isimli constraint'ler. CREATE TABLE ve constraint yazımının ayrıntısı SQL Temelleri serisinin 3. ve 4. yazılarında; burada odak, her satırın hangi requirement'tan geldiği.
CREATE TABLE dbo.books (
book_id INT IDENTITY(1,1) NOT NULL,
isbn CHAR(13) NOT NULL,
title NVARCHAR(200) NOT NULL,
list_price DECIMAL(10,2) NOT NULL,
CONSTRAINT PK_books PRIMARY KEY (book_id),
CONSTRAINT UQ_books_isbn UNIQUE (isbn),
CONSTRAINT CK_books_list_price CHECK (list_price >= 0)
);
CREATE TABLE dbo.authors (
author_id INT IDENTITY(1,1) NOT NULL,
first_name NVARCHAR(100) NOT NULL,
last_name NVARCHAR(100) NOT NULL,
CONSTRAINT PK_authors PRIMARY KEY (author_id)
);
CREATE TABLE dbo.book_authors (
book_id INT NOT NULL,
author_id INT NOT NULL,
author_order TINYINT NOT NULL,
CONSTRAINT PK_book_authors PRIMARY KEY (book_id, author_id),
CONSTRAINT FK_book_authors_books FOREIGN KEY (book_id) REFERENCES dbo.books (book_id),
CONSTRAINT FK_book_authors_authors FOREIGN KEY (author_id) REFERENCES dbo.authors (author_id)
);
CREATE TABLE dbo.orders (
order_id INT NOT NULL,
ordered_at DATETIME2(0) NOT NULL,
CONSTRAINT PK_orders PRIMARY KEY (order_id)
);
CREATE TABLE dbo.order_items (
order_item_id INT IDENTITY(1,1) NOT NULL,
order_id INT NOT NULL,
book_id INT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
CONSTRAINT PK_order_items PRIMARY KEY (order_item_id),
CONSTRAINT UQ_order_items_order_book UNIQUE (order_id, book_id),
CONSTRAINT FK_order_items_orders FOREIGN KEY (order_id) REFERENCES dbo.orders (order_id),
CONSTRAINT FK_order_items_books FOREIGN KEY (book_id) REFERENCES dbo.books (book_id),
CONSTRAINT CK_order_items_quantity CHECK (quantity > 0)
);
UQ_books_isbn R2'nin, book_authors tablosu ve içindeki author_order R1'in, order_items.quantity ile UQ_order_items_order_book R3'ün, order_items.unit_price ise R4'ün karşılığı. orders tablosunu burada yalnızca iki kolonla bıraktım; müşteri ve status kolonları sonraki yazılarda gelecek. Şimdi R4'ün gerçekten tuttuğunu görelim: bir sipariş oluşturup ardından kataloğun fiyatını değiştiriyoruz.
INSERT INTO dbo.books (isbn, title, list_price) VALUES ('9798900000268', N'Dune', 390.50);
INSERT INTO dbo.orders (order_id, ordered_at) VALUES (1003, '2026-03-09T10:15:00');
INSERT INTO dbo.order_items (order_id, book_id, quantity, unit_price) VALUES (1003, 1, 2, 351.45);
UPDATE dbo.books SET list_price = 420.00 WHERE isbn = '9798900000268';
SELECT b.title, b.list_price, oi.order_id, oi.quantity, oi.unit_price
FROM dbo.books AS b
JOIN dbo.order_items AS oi ON oi.book_id = b.book_id;
(1 rows affected)
(1 rows affected)
(1 rows affected)
(1 rows affected)
title list_price order_id quantity unit_price
----- ---------- -------- -------- ----------
Dune 420.00 1003 2 351.45
(1 rows affected)
Katalog fiyatı 420.00 oldu, 1003 numaralı siparişin kalemi hâlâ 351.45 gösteriyor. Bu davranışı bir trigger ya da uygulama kodu sağlamıyor; modelin kendisi sağlıyor, çünkü iki fiyat iki ayrı olgu olarak iki ayrı yerde duruyor. Baştaki EF Core modelinde ise Prices listesi kalemle değil siparişle birlikte duruyordu ve "bu fiyat hangi kitabın?" sorusunun cevabı yalnızca array'deki pozisyondu.
Serinin Çalışma Malzemesi: Sipariş Excel'i
Kitapçının bugünkü gerçeği ise şu dosya. Tek sheet, her satır bir sipariş, bir siparişteki kitaplar virgülle ayrılmış, yazarlar noktalı virgül ve virgülle iç içe yazılmış. Excel'den CSV (Comma-Separated Values) olarak dışarı aldığımız hâli:
order_no,order_date,customer,email,phone,city,region,shipping_address,isbns,books,authors,prices,quantities,total
1001,2026-03-02,Ada Lovelace,ada@example.com,+90 532 000 0001,Istanbul,Marmara,"Moda Cd. 12, Kadikoy","9798900000268, 9798900000428","Dune, Good Omens","Frank Herbert; Terry Pratchett, Neil Gaiman","390.50, 340.90","1, 1",731.40
1002,2026-03-05,Alan Turing,alan@example.com,+90 533 000 0002,Ankara,Central Anatolia,"Tunali Hilmi Cd. 5, Cankaya",9798900000572,The Pragmatic Programmer,"Andrew Hunt, David Thomas",1150.00,1,1150.00
1003,2026-03-09,Ada Lovelace,ada@example.com,+90 532 000 0001,Istanbul,Marmara,"Moda Cd. 12, Kadikoy","9798900000305, 9798900000268","The Left Hand of Darkness, Dune","Ursula K. Le Guin; Frank Herbert","660.00, 351.45","1, 2",1362.90
1004,2026-03-12,Grace Hopper,grace@example.com,+90 535 000 0003,Izmir,Aegean,"Kibris Sehitleri Cd. 40, Konak",9798900000411,A Wizard of Earthsea,Ursula Le Guin,200.50,3,601.50
1005,2026-03-15,Alan Turing,alan@example.com,+90 533 000 0002,Ankara,Central Anatolia,"Tunali Hilmi Cd. 5, Cankaya",9798900000428,Good Omens,"Terry Pratchett, Neil Gaiman",340.90,1,340.90
Bu dosyayı yadırgama; gerçek hayatta çoğu sistem böyle başlar ve bu dosya aylarca işini gördü. Ama içinde serinin bütün konuları saklı. 1003 numaralı siparişte Dune 351.45'e satılmış, 1001'de 390.50'ye; yani fiyat kitabın değil kalemin bilgisi. Le Guin 1003'te "Ursula K. Le Guin", 1004'te "Ursula Le Guin" olarak yazılmış. Ada'nın telefonu iki satırda tekrar ediyor ve birini güncelleyip diğerini unutmak an meselesi. Şehirden bölge çıkıyor ama ikisi de her satırda ayrı yazılı. total kolonu fiyat ve adetten hesaplanabiliyor. Bu dosyayı serinin 5. yazısında SQL Server'a olduğu gibi yükleyip insert, update ve delete anomaly'lerini canlı göreceğiz, 6. yazıda ise 1NF, 2NF ve 3NF ile adım adım tablolara bölüp Bookstore şemasına ulaşacağız.
Üretimde Dikkat
Modeli kodun yanında tut. Bir Confluence sayfasında duran ve son güncellemesi iki yıl önce olan ER diyagramı, hiç diyagram olmamasından daha tehlikelidir, çünkü insanlar ona güvenir. Bir sonraki yazıda ER diyagramını Mermaid ile metin olarak repository'de tutmayı ve pull request'te diff'lemeyi göreceğiz.
Şema değişikliğinin maliyetini baştan hesaba kat. Yayına çıkmış bir tabloda kolonun anlamını değiştirmek, yeni kolon ekleyip veriyi taşımak, eski kolonu okuyan herkesin geçmesini beklemek ve sonra eskiyi kaldırmak demektir. Bu adımların deploy tarafı Deployment Stratejileri serisinin "Migration'ların Deploy'daki Yeri" yazısında; modelleme tarafında yapabileceğin şey, değişmesi muhtemel kararları (e-postanın kimlik olması gibi) en baştan key'e koymamak.
Requirement'ları ve access pattern listesini şema review'ının girdisi yap. "Bu kolon neden nullable?", "Bu tablo neden ayrı?" sorularının cevabı bir requirement numarasına bağlanabiliyorsa model savunulabilir demektir. Bağlanamıyorsa ya requirement eksik ya kolon fazla. Serinin son yazısında bunu bir şema review checklist'ine dönüştüreceğiz.
ORM'i (Object-Relational Mapping) modelin aracı yap, modelin sahibi değil. EF Core'da code-first çalışmak tamamen meşru; ama migration'ın ürettiği SQL'i her seferinde okuyup "Bu tabloyu ben tasarlasaydım böyle mi kurardım?" diye sor. EF Core serisinin "EF Core Migrations" yazısında migration'ın ürettiği script'i almanın yolları var.
Sık Düşülen Tuzaklar
Şemayı ORM class'larından "kendiliğinden" türetmek. Yazının başındaki örnek bunun ta kendisi: class ekranı taklit etti, tablo da class'ı taklit etti ve araya kimse karar koymadı. Varsayılanlar (her metin nvarchar(max), her decimal decimal(18,2), her liste JSON) teknik olarak çalışan ama iş kurallarından habersiz bir şema üretir.
Tabloyu ekran tasarımına göre kurmak. Ekran bir access pattern'dir, model değildir. Bugün sipariş ekranında müşteri adı, kitaplar ve toplam aynı kartta duruyor diye bunlar aynı tabloda durmak zorunda değil; yarın aynı veri mobil uygulamada başka bir düzende gösterilecek, rapor ekranında bambaşka bir gruplamayla.
Requirement'taki görünmez entity'yi kaçırmak. Sipariş kalemi gibi iş biriminin isim vermediği kavramlar genellikle bir attribute'un "nereye ait olduğunu" sorunca ortaya çıkar. "Bu bilgi kimin bilgisi?" sorusunu her attribute için sor.
Bir kopyayı tekrar sanmak ya da bir tekrarı kopya sanmak. unit_price ile list_price aynı değeri taşısa bile iki ayrı olgudur. Tersine, her satırda yeniden yazılan müşteri telefonu ayrı bir olgu değil, aynı olgunun tekrarıdır. Hangisinin hangisi olduğuna veriye bakarak değil, iş kuralına bakarak karar verilir.
Access pattern'leri hiç yazmamak ya da modeli onlara göre kurmak. İki uç da kötü: listesiz physical tasarım tahmindir, listeye göre bükülmüş logical model ise ilk yeni ekranda kırılır. Logical model veriyi, physical tasarım erişimi gözetir.
Küçük Bir Deneme
★☆☆ Kitapçı "hediye çeki" satmak istiyor: her çekin bir kodu var, bir tutarı var, bir müşteriye verilebilir ve birden çok siparişte parça parça kullanılabilir. Bu cümlelerden entity, ilişki ve kural adaylarını çıkar. Görünmeyen bir entity var mı?
★★☆ Yazının başındaki Order class'ını Customer, Book ve OrderItem class'larına böl, GenerateCreateScript() çıktısını yeniden al ve iki script'i karşılaştır. Hangi kolonların tipine hâlâ framework karar veriyor?
★★★ Kitapçıya "yazar sayfası" ekleniyor: yazarın biyografisi, bütün kitapları, her kitabın ortalama puanı ve yazarın birlikte yazdığı diğer yazarlar. Bu sayfa için access pattern'i yaz ve bugünkü modelde hangi tabloları birleştirmen gerektiğini listele. Modelde eksik bir şey var mı?
Modelin üç seviyesini ve requirement'tan entity çıkarmayı gördük. Bir sonraki yazıda conceptual ve logical modelin ortak dili olan ER modeling'e geçiyoruz: entity ve attribute türleri, cardinality ve optionality, Chen ile Crow's Foot notation'larının aynı modeli nasıl çizdiği ve Bookstore'un ilk ER taslağını Mermaid ile kodda tutmak.