---
title: 'Nesne–İlişki Uyumsuzluğu'
source: 'https://academia.sh/tr/kurslar/veri-erisim-katmani/nesne-iliski-uyumsuzlugu'
course: 'Veri Erişim Katmanı ve İş Mantığı'
language: tr
updated: '2026-08-17T18:06:50+00:00'
license: 'CC BY-SA 4.0'
---

# Nesne–İlişki Uyumsuzluğu

Nesne modeli ile ilişkisel modelin örtüşmediği dört nokta: kimlik, kalıtım, ilişki yönü ve tanecik. Her uyumsuzluğun eşleme kararıyla nasıl kapatıldığı ölçülerek gösterilir.

Önceki ders küçük bir eşleyici kurdu ve orada `Odunc` tipi ile `odunc` bağıntısı bire bir
örtüştü: her alan bir sütun, her ilişki bir yabancı anahtardı. Bu örtüşme kolay bir örnekten
gelir, kuraldan değil.

Nesne modeli ile ilişkisel model iki ayrı kuramın ürünüdür. Nesne modelinde kimlik
başvurudur, kalıtım vardır, bağlar iki yönlüdür ve bir nesnenin içine başka nesneler
gömülebilir. İlişkisel modelde kimlik anahtar değeridir, kalıtım yoktur, bağ yabancı
anahtarla tek yönlü kurulur ve tablo düz bir demet listesidir. Bu iki modelin örtüşmeyen
noktalarına **nesne–ilişki uyumsuzluğu** (object–relational impedance mismatch) denir.
Uyumsuzluk bir hata değil, kapatılması gereken bir açıklıktır. Ders dört açıklığı sırayla
ölçer.

Aşağıdaki blok bu dersin ilk bölümünde kullanılan veritabanını kurar.

```sh
rm -f kutuphane.db
sqlite3 kutuphane.db <<'SQL'
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL,
                  eposta TEXT, kayit_tarihi TEXT NOT NULL);
CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL,
                    basim_yili INTEGER);
CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id),
                    uye_id INTEGER NOT NULL REFERENCES uye(uye_id), alis_tarihi TEXT NOT NULL,
                    iade_tarihi TEXT);
INSERT INTO uye VALUES (1,'Ayşe','Demir','ayse@ornek.test','2023-02-14'),
  (2,'Mehmet','Kaya','mehmet@ornek.test','2023-05-30'),(3,'Zeynep','Arslan',NULL,'2024-01-09');
INSERT INTO kitap VALUES (1,'Körlük','José Saramago',1995),(6,'Anayurt Oteli','Yusuf Atılgan',NULL);
INSERT INTO odunc VALUES (3,1,2,'2025-02-11',NULL),(11,6,2,'2025-06-11','2025-06-25');
SQL
```

## Kimlik Uyumsuzluğu

Bir bağıntıda iki satırın "aynı" olması birincil anahtarlarının eşit olması demektir.
Nesne dünyasında ise iki tür eşitlik vardır: aynı başvuru olmak ve aynı değeri taşımak.
Eşleyici satırı nesneye çevirirken bu iki eşitlik ayrışır.

```js
// kimlik-farki.mjs — ayni satirin iki kez okunmasi iki ayri nesne uretir
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("kutuphane.db");

const oku = (id) => db.prepare("SELECT uye_id, ad, soyad FROM uye WHERE uye_id = ?").get(id);

const a = oku(2);
const b = oku(2);

console.log("ayni satir mi (birincil anahtar):", a.uye_id === b.uye_id);
console.log("ayni nesne mi (basvuru):        ", a === b);

a.ad = "Mehmet Ali";
console.log("a.ad:", a.ad, "| b.ad:", b.ad);

const harita = new Map();
const okuHaritali = (id) => {
  if (!harita.has(id)) harita.set(id, oku(id));
  return harita.get(id);
};
const c = okuHaritali(2), d = okuHaritali(2);
c.ad = "Mehmet Ali";
console.log("kimlik haritasiyla ayni nesne mi:", c === d, "| d.ad:", d.ad);
```

```sh
node kimlik-farki.mjs
```

```
ayni satir mi (birincil anahtar): true
ayni nesne mi (basvuru):         false
a.ad: Mehmet Ali | b.ad: Mehmet
kimlik haritasiyla ayni nesne mi: true | d.ad: Mehmet Ali
```

İki okuma aynı satırı getirdi ama iki ayrı nesne üretti. Birinde yapılan değişiklik
ötekinde görünmüyor; iki nesne de aynı satıra yazılırsa biri diğerini eziyor. Çıktının son
satırı çözümü gösteriyor: önceki derste kurulan **kimlik haritası**, bir isteğin ömrü
boyunca her satırı tek nesneyle temsil eder ve iki eşitliği yeniden çakıştırır.

Bunun ikinci bir sonucu vardır. Veritabanına henüz yazılmamış bir nesnenin birincil
anahtarı yoktur. Anahtarı kimliğin tek ölçütü yaparsan, kaydedilmemiş iki nesne birbirine
eşit görünür. Bu yüzden eşleme katmanında yeni nesneler ya uygulama tarafından üretilen bir
kimlikle doğar ya da anahtar atanana kadar yalnız başvuru eşitliğiyle karşılaştırılır.

## Kalıtım Uyumsuzluğu

Kütüphane hem basılı hem sesli eserler tutmaya başlarsa nesne modelinde bir üst tip ve iki
alt tip belirir: ortak alanlar üstte, özel alanlar altta. İlişkisel modelde alt tip diye bir
şey yoktur. Hiyerarşi üç yoldan tabloya indirilebilir.

```sh
rm -f kalitim.db
sqlite3 kalitim.db <<'SQL'
-- 1. Tek tablo: butun alt turler tek baginti, ayirt edici sutunla
CREATE TABLE tek_tablo_eser (
  eser_id INTEGER PRIMARY KEY, tur TEXT NOT NULL, baslik TEXT NOT NULL, yazar TEXT NOT NULL,
  sayfa_sayisi INTEGER, sure_dakika INTEGER, seslendiren TEXT);
INSERT INTO tek_tablo_eser VALUES
  (1,'basili','Körlük','José Saramago',352,NULL,NULL),
  (2,'basili','Tutunamayanlar','Oğuz Atay',724,NULL,NULL),
  (3,'sesli','Kum Kitabı','Jorge Luis Borges',NULL,214,'Deniz Ak'),
  (4,'sesli','Yaban','Yakup Kadri',NULL,398,'Ece Gür');

-- 2. Somut tur basina tablo: ortak sutunlar her tabloda tekrarlanir
CREATE TABLE somut_basili (eser_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL,
  yazar TEXT NOT NULL, sayfa_sayisi INTEGER NOT NULL);
CREATE TABLE somut_sesli (eser_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL,
  yazar TEXT NOT NULL, sure_dakika INTEGER NOT NULL, seslendiren TEXT NOT NULL);
INSERT INTO somut_basili VALUES (1,'Körlük','José Saramago',352),(2,'Tutunamayanlar','Oğuz Atay',724);
INSERT INTO somut_sesli VALUES (3,'Kum Kitabı','Jorge Luis Borges',214,'Deniz Ak'),
  (4,'Yaban','Yakup Kadri',398,'Ece Gür');

-- 3. Tur basina tablo: ortak alanlar ustte, ozel alanlar alt bagintida
CREATE TABLE eser (eser_id INTEGER PRIMARY KEY, tur TEXT NOT NULL,
  baslik TEXT NOT NULL, yazar TEXT NOT NULL);
CREATE TABLE eser_basili (eser_id INTEGER PRIMARY KEY REFERENCES eser(eser_id),
  sayfa_sayisi INTEGER NOT NULL);
CREATE TABLE eser_sesli (eser_id INTEGER PRIMARY KEY REFERENCES eser(eser_id),
  sure_dakika INTEGER NOT NULL, seslendiren TEXT NOT NULL);
INSERT INTO eser VALUES (1,'basili','Körlük','José Saramago'),(2,'basili','Tutunamayanlar','Oğuz Atay'),
  (3,'sesli','Kum Kitabı','Jorge Luis Borges'),(4,'sesli','Yaban','Yakup Kadri');
INSERT INTO eser_basili VALUES (1,352),(2,724);
INSERT INTO eser_sesli VALUES (3,214,'Deniz Ak'),(4,398,'Ece Gür');
SQL
```

Üçü de aynı dört eseri saklıyor. Fark, "bütün eserleri getir" isteğinin maliyetinde
görünür.

```js
// kalitim-olc.mjs — uc esleme stratejisinde sorgu ve bos deger sayisi
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("kalitim.db");

function olc(ad, sorgular) {
  let bosDeger = 0, satir = 0;
  for (const s of sorgular) {
    for (const r of db.prepare(s).all()) {
      satir += 1;
      bosDeger += Object.values(r).filter((v) => v === null).length;
    }
  }
  console.log(`${ad.padEnd(22)} sorgu=${sorgular.length}  satir=${satir}  bos_deger=${bosDeger}`);
}

olc("tek tablo", ["SELECT * FROM tek_tablo_eser"]);
olc("somut tur basina", ["SELECT * FROM somut_basili", "SELECT * FROM somut_sesli"]);
olc("tur basina (birlesik)", [
  `SELECT e.eser_id, e.tur, e.baslik, e.yazar, b.sayfa_sayisi, s.sure_dakika, s.seslendiren
   FROM eser e LEFT JOIN eser_basili b ON b.eser_id = e.eser_id
               LEFT JOIN eser_sesli  s ON s.eser_id = e.eser_id`,
]);
```

```sh
node kalitim-olc.mjs
```

```
tek tablo              sorgu=1  satir=4  bos_deger=6
somut tur basina       sorgu=2  satir=4  bos_deger=0
tur basina (birlesik)  sorgu=1  satir=4  bos_deger=6
```

Sayılar üç stratejinin karakterini veriyor. **Tek tablo** tek sorguyla okur ama boş değer
üretir; alt tipe özgü her sütun, öteki alt tipin satırlarında `NULL` kalır. Alt tipe özgü
alanlar `NOT NULL` yapılamaz, çünkü kısıt bütün satırlara uygular. **Somut tür başına
tablo** hiç boş değer üretmez ve `NOT NULL` kısıtına izin verir; bedeli sorgu sayısıdır ve
üst tip üzerinden sorulan her soru birleşim gerektirir. **Tür başına tablo** hiyerarşiyi
şemaya birebir yansıtır; okumada dış birleştirme, yazmada iki tabloya ekleme ister.

Somut tür başına tablo bir kısıt daha kaybettirir: hiyerarşinin tamamına başvuran bir
yabancı anahtar kurulamaz.

```sh
sqlite3 kalitim.db <<'SQL'
PRAGMA foreign_keys = ON;
CREATE TABLE rezervasyon (rez_id INTEGER PRIMARY KEY,
  eser_id INTEGER NOT NULL REFERENCES somut_basili(eser_id), uye_id INTEGER NOT NULL);
INSERT INTO rezervasyon VALUES (1, 1, 3);
INSERT INTO rezervasyon VALUES (2, 3, 3);
SQL
```

```
Runtime error near line 5: FOREIGN KEY constraint failed (19)
```

Basılı esere yapılan rezervasyon geçti, sesli esere yapılan reddedildi. Yabancı anahtar tek
bir bağıntıyı gösterebilir; hiyerarşi iki bağıntıya bölündüğünde başvuru bütünlüğü
uygulamaya devredilir. Üst tipe başvuru gerekiyorsa tür başına tablo stratejisi seçilir,
çünkü orada `eser` bağıntısı bütün hiyerarşiyi temsil eder.

## İlişki Yönü Uyumsuzluğu

Nesne grafiğinde bir bağ tek yönlüdür; iki yön isteniyorsa iki ayrı başvuru tutulur ve
ikisi elle tutarlı kılınır. İlişkisel modelde tek bir yabancı anahtar sütunu her iki yönü
de yanıtlar.

```js
// yon-farki.mjs — nesne tarafinda iki yon, iliskisel tarafta tek yabanci anahtar
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("kutuphane.db");

// Nesne grafigi: iki yonlu bag. Iki taraf da elle tutulur.
const uye = { id: 2, ad: "Mehmet", oduncler: [] };
const odunc = { id: 99, kitapId: 6, uye: null };

odunc.uye = uye;                       // yalniz bir yon kuruldu
console.log("odunc.uye.id:", odunc.uye.id);
console.log("uye.oduncler.length:", uye.oduncler.length);

uye.oduncler.push(odunc);              // ikinci yon elle eklenir
console.log("ikinci yon kurulduktan sonra:", uye.oduncler.length);

// Iliskisel taraf: tek sutun iki yonu de tasir.
db.exec("CREATE TEMP TABLE gecici AS SELECT * FROM odunc");
db.prepare("INSERT INTO gecici VALUES (?,?,?,?,NULL)").run(99, 6, 2, "2025-07-01");
const ileri = db.prepare("SELECT uye_id FROM gecici WHERE odunc_id = 99").get();
const geri = db.prepare("SELECT odunc_id FROM gecici WHERE uye_id = 2 ORDER BY odunc_id").all();
console.log("ileri yon (odunc -> uye):", ileri.uye_id);
console.log("geri yon (uye -> odunc):", geri.map((r) => r.odunc_id).join(", "));
```

```sh
node yon-farki.mjs
```

```
odunc.uye.id: 2
uye.oduncler.length: 0
ikinci yon kurulduktan sonra: 1
ileri yon (odunc -> uye): 2
geri yon (uye -> odunc): 3, 11, 99
```

Nesne tarafında bir yön kurulduğunda öteki yön boş kaldı; ilişkisel tarafta tek satır her
iki soruyu da yanıtladı. Bu farkın eşleme kararı **ilişkinin sahibini seçmektir**: hangi
tarafın yazması yabancı anahtarı değiştirir, öteki taraf yalnız okur. Sahip seçilmezse iki
taraftan gelen iki güncelleme birbiriyle çelişir ve hangisinin diske indiği çağrı sırasına
bağlı kalır.

Çoktan çoğa ilişkilerde uyumsuzluk daha da belirgindir. Nesne tarafında iki listeyle
kurulan bağın ilişkisel karşılığı yoktur; SQL Temelleri kursunda tanıtılan bağlantı
bağıntısı zorunludur. Bağlantı bağıntısının kendi öznitelikleri varsa (ödünç tarihi gibi)
bu bağıntı artık bir bağ değil, kendi başına bir varlıktır ve nesne modeline de varlık
olarak yansımalıdır.

## Tanecik Uyumsuzluğu

Nesne modelinde her kavram ayrı bir tip olabilir. Üyenin adresi `Adres` tipiyle temsil
edilirse, bu tipin kimliği yoktur; iki adres aynı alanları taşıyorsa aynıdır. Kimliği
olmayan, yalnız değeriyle tanımlanan bu tiplere **değer nesnesi** (value object) denir.

İlişkisel modelde her tablonun bir birincil anahtarı vardır. Değer nesnesine tablo verirsen
ona olmayan bir kimlik uydurmuş olursun; vermezsen alanlarını sahip bağıntının içine
gömersin. İkinci karar **gömme** (embedding) adını alır ve genellikle doğru olandır: `uye`
bağıntısı `adres_il`, `adres_ilce`, `adres_posta_kodu` sütunlarını taşır, `Adres` tipi
eşleyici tarafından bu üç sütundan kurulur.

Karar ölçütü paylaşımdır. Değer nesnesi birden çok sahip tarafından paylaşılıyor ve
tek noktadan güncellenmesi gerekiyorsa gömme yetmez; o zaman kavram aslında bir varlıktır
ve kimliği hak eder. Kütüphane örneğinde adres üyeye özeldir, gömülür; şube ise kitap ve
personel tarafından paylaşılır, kendi bağıntısında durur.

## Özet

- Nesne–ilişki uyumsuzluğu kimlik, kalıtım, ilişki yönü ve tanecik olmak üzere dört
  noktada ortaya çıkar; her biri ayrı bir eşleme kararıyla kapatılır.
- Aynı satırın iki kez okunması iki ayrı nesne üretti; kimlik haritası satır ile nesne
  arasındaki tekliği geri kurdu.
- Kalıtımın üç stratejisi ölçüldü: tek tablo 1 sorgu ve 6 boş değer, somut tür başına tablo
  2 sorgu ve 0 boş değer, tür başına tablo 1 sorgu ve 6 boş değer üretti.
- Somut tür başına tablo stratejisinde hiyerarşinin tamamına başvuran yabancı anahtar
  kurulamadı; başvuru bütünlüğü uygulamaya devredildi.
- İlişki yönü uyumsuzluğu sahibin seçilmesiyle, tanecik uyumsuzluğu değer nesnesinin
  sahip bağıntıya gömülmesiyle kapatılır.

## Sonraki Adım

Uyumsuzluğu kapatan kararlar şimdiye kadar çağıran kodun içine dağıldı: hangi stratejinin
seçildiği, hangi ilişkinin sahibi olduğu, hangi alanın gömüldüğü bilgisi sorguyu yazan her
yerde tekrarlanıyor. Bu bilgiyi tek bir yerde toplayan, çağıran tarafa yalnız alan
kavramlarıyla konuşan bir arayüz bırakan yapıya depo kalıbı denir. Sonraki ders bu arayüzü
kurar ve kalıcılık ayrıntısının gerçekten gizlendiğini, deponun sahte bir uygulamasıyla iş
mantığını veritabanı olmadan sınayarak gösterir.
