ENTITY FRAMEWORK CORE İLE ÇOKA ÇOK İLİŞKİ NASIL YAPILIR?

Bu dersimizde de çoka çok ilişkiden bahsetmek istiyorum. Uygulamamızı düşündüğümüzde, bir yazarın birden fazla kitabı olabilir, aynı şekilde bir kitabı birden fazla kişi de yazabilir. Dolayısı ile bu iki tablo arasında çoka çok ilişki var olur.

Bu tarzda bir ilişkiyi kurabilmek için biz mapping table adını verdiğimiz bir ara tablo kullanacağız.

Detaylı anlatım ve kod takibi için video:

Bu ara tablo ile iki tabloyu çoka çok ilişki ile bağlayacağız. Bunu yapabilmek için uygulamamda Models klasörü altında KitapYazar diye bir model class daha oluşturuyorum. İçine geliyor propertyleri ve navigation propertyleri ekliyorum.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GRSYKitapEvi_Model.Models
{
    public class KitapYazar
    {
        [ForeignKey("Kitap")]
        public int Kitap_Id { get; set; }

        [ForeignKey("Yazar")]
        public int Yazar_Id { get; set; }

        public Kitap Kitap { get; set; }
        public Yazar Yazar { get; set; }
    }
}

Şimdi değinmek istediğim bir nokta var, biz bu serinin bir önceki derslrinde her bir tablonun mutalaka en az bir primary key alanına sahip olması gerektiğinden bahsettik. Benim bu tablomda ise birden fazla primary key kullanmam lazım. İşte böyle durumlarda biz birleşik primary key yani composite key kullanırız. Composite Key, birden fazla primary key kullanılması durumudur.

Peki composite key nasıl olacak?

Ben burada her iki id bilgisini tutan propertyler için direkt KEY data annotations kullanamam. Uygulamam hata verir. O halde ne yapıyoruz, öncelikle; buradan ApplicationDbContext clasıma geliyorum.

İşte burada fluent api ile composite key oluşturacağım. Peki fluent api nedir? Kısaca, code-fisrt yaklaşımı ile veritabanı classlarını ve ilişkilerini yapılandırmak için kullandığımız bir yol. Bu dersten sonra fluent_api  yapısına ayrıntılı değineceğim zaten, şimdilik bu kadar bilin yeter.

Fluent api ile ben ApplicationDbContext classım içinde OnModelCrating metodunu override edeceğim.

using GRSYKitapEvi_Model.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GRSYKitapEvi_DataAccess.Data
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions< ApplicationDbContext> options) : base(options)
        {

        }

        //public DbSet< Kategori> Kategoriler { get; set; }
        public DbSet< Tur> Turler { get; set; }
        public DbSet< Kitap> Kitaplar { get; set; }
        public DbSet< YayinEvi> YayinEvleri { get; set; }
        public DbSet< Yazar> Yazarlar { get; set; }
        public DbSet< KitapYazar> KitapYazarlar { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity< KitapYazar>().HasKey(x => new { x.Yazar_Id, x.Kitap_Id });
        }
    }
}

Buradan Kitap classıma gidiyorum..

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GRSYKitapEvi_Model.Models
{
    [Table("tb_Kitap")]
    public class Kitap
    {
        [Key]         

        public int Kitap_Id { get; set; }

        [Required]
        public string KitapAdi { get; set; }

        [Required]
        public double Fiyat  { get; set; }

        [Required]
        [MaxLength(13)]
        public string ISBN { get; set; }

        //[ForeignKey("Kategori")]
        //public int KategoriId { get; set; }

        public Kategori Kategori { get; set; }

        [ForeignKey("KitapDetay")]
        public int KitapDetay_Id { get; set; }
        public KitapDetay KitapDetay { get; set; }

        [ForeignKey("YayinEvi")]
        public int YayinEvi_Id { get; set; }
        public YayinEvi YayinEvi { get; set; }

        public ICollection< KitapYazar> KitapYazarlar { get; set; }

    }
}

Aynısını Yazar tablosuna da ekliyorum.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GRSYKitapEvi_Model.Models
{
    [Table("tb_Yazar")]
    public class Yazar
    {
        [Key]
        public int Yazar_Id { get; set; }

        [Required]
        public string YazarAd { get; set; }

        [Required]
        public string YazarSoyad { get; set; }

        public string Lokasyon { get; set; }
        public DateTime DogumTarihi { get; set; }

        [NotMapped]
        public string AdSoyad
        {
            get 
            { return $"{YazarAd}  {YazarSoyad}";
            
            }
        }

        public ICollection< KitapYazar> KitapYazarlar { get; set; }


    }
}

Akabinde migration oluşturuyorum. Package manager console ekranında aşağıdaki komutu yazıyorum:

Add-migration EkleCokaCokIliskiKitapYazar

Migration içeriğimiz:

using Microsoft.EntityFrameworkCore.Migrations;

namespace GRSYKitapEvi_DataAccess.Migrations
{
    public partial class EkleCokaCokIliskiKitapYazar : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropForeignKey(
                name: "FK_tb_Kitap_tb_Kategori_KategoriId",
                table: "tb_Kitap");

            migrationBuilder.AlterColumn< int>(
                name: "KategoriId",
                table: "tb_Kitap",
                type: "int",
                nullable: true,
                oldClrType: typeof(int),
                oldType: "int");

            migrationBuilder.CreateTable(
                name: "KitapYazarlar",
                columns: table => new
                {
                    Kitap_Id = table.Column< int>(type: "int", nullable: false),
                    Yazar_Id = table.Column< int>(type: "int", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_KitapYazarlar", x => new { x.Yazar_Id, x.Kitap_Id });
                    table.ForeignKey(
                        name: "FK_KitapYazarlar_tb_Kitap_Kitap_Id",
                        column: x => x.Kitap_Id,
                        principalTable: "tb_Kitap",
                        principalColumn: "Kitap_Id",
                        onDelete: ReferentialAction.Cascade);
                    table.ForeignKey(
                        name: "FK_KitapYazarlar_tb_Yazar_Yazar_Id",
                        column: x => x.Yazar_Id,
                        principalTable: "tb_Yazar",
                        principalColumn: "Yazar_Id",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateIndex(
                name: "IX_KitapYazarlar_Kitap_Id",
                table: "KitapYazarlar",
                column: "Kitap_Id");

            migrationBuilder.AddForeignKey(
                name: "FK_tb_Kitap_tb_Kategori_KategoriId",
                table: "tb_Kitap",
                column: "KategoriId",
                principalTable: "tb_Kategori",
                principalColumn: "KategoriId",
                onDelete: ReferentialAction.Restrict);
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropForeignKey(
                name: "FK_tb_Kitap_tb_Kategori_KategoriId",
                table: "tb_Kitap");

            migrationBuilder.DropTable(
                name: "KitapYazarlar");

            migrationBuilder.AlterColumn< int>(
                name: "KategoriId",
                table: "tb_Kitap",
                type: "int",
                nullable: false,
                defaultValue: 0,
                oldClrType: typeof(int),
                oldType: "int",
                oldNullable: true);

            migrationBuilder.AddForeignKey(
                name: "FK_tb_Kitap_tb_Kategori_KategoriId",
                table: "tb_Kitap",
                column: "KategoriId",
                principalTable: "tb_Kategori",
                principalColumn: "KategoriId",
                onDelete: ReferentialAction.Cascade);
        }
    }
}

ve update database ile veritabanımı güncelliyorum. Package-manager console ekranımda aşağıdaki komutu yazıyorum.

update-database

Bir sonraki derste görüşmek üzere..

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir