Entity Framework Core - Bire Çok İlişkili Tablolarla Çalışmak

Entity Framework Core'de tanımlanan ilişki türlerinden bire çok (One to Many) ilişki, "bir tablodaki bir verinin, diğer tablodaki birden fazla veri ile ilişkisi olduğu" ilişki türüdür.

Örnek olarak; bir departmana ait, birden fazla personel bulunması verilebilir. Kullanılan entityler: Department - Personal

Entityler arasında bire çok ilişki tanımlayabilmek için entitylerde aşağıdaki gibi navigation property adı verilen propertyler eklenmelidir. 

public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public List<Personal> Personals { get; set; } //Navigation property
}
public class Personal
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string PhoneNumber { get; set; }
public int? ManagerId { get; set; }
public int DepartmentId { get; set; }
public bool IsActive { get; set; }
public Department Department { get; set; } //Navigation property
}
view raw Entity.cs hosted with ❤ by GitHub

Department sınıfında List<Personal> tipinde liste verilmesi, bir departmana bağlı personelleri belirtir. Code first ile ilişki kurarken varsayılan olarak bire çok ilişkiyi algılayacaktır. Aynı zamanda departman tanımlarken aynı anda bu departmanla ilişkili personelleri de tanımlayabiliriz. 

Personal sınıfındaki DepartmentId property ise otomatik olarak Departman tablosundaki Id kolonunun foreign key olarak işaretlenmesini sağlayan bir kullanımdır. 

public class PersonalMapping : IEntityTypeConfiguration<Personal>
{
public void Configure(EntityTypeBuilder<Personal> builder)
{
builder.HasKey(c => c.Id);
builder.Property(c => c.Id).ValueGeneratedOnAdd();
builder.Property(c => c.Name).HasMaxLength(50).IsRequired();
//One to many relationship
builder.HasOne(u => u.Department).WithMany(r => r.Personals);
}
}

Yukarıdaki kod bloğunda Personal sınıfı için oluşturulan ilgili mapping sınıfında FluentAPI metotlarından HasOne ve WithMany kullanıldı. Kullanırken navigation propertylerden yararlanıldı. Kodu bir departman, birden fazla personel ile ilişkili olur şeklinde okuyabiliriz. 

Migration işlemini gerçekleştirdikten sonra veri tabanında tablolar ve keyler, aşağıdaki gibi yansıyacaktır.

Diyagramdan da ilişki anlaşılacaktır.
Geliştirmeleri veri tabanına yansıttıktan sonra, verilerle çalışma işlemine geçebiliriz. 

Yeni bir kayıt ekleme - Insert işlemi için örnek kodumuz

Personel listesi oluşturulup, departmana bağlanmasıdır. Department tablosundaki Personals propertysine personeller atanır. Departman bilgisi tanımlandıktan sonra Add metodu ile eklenip, SaveChanges metodu ile veri tabanına yansıtma işlemi yapılır.

public void Add_Department_WithPersonal()
{
using (var dbContext = new PhoneBookDbContext())
{
var personalList = new List<Personal>
{
new Personal { Name="Mert",Surname="Metin",PhoneNumber="02125555555"},
new Personal { Name="Ali",Surname="Metin",PhoneNumber="02125555555"}
};
var department = new Department
{
Name = "Yazılım",
Personals = personalList
};
dbContext.Departments.Add(department);
dbContext.SaveChanges();
}
}
view raw Insert.cs hosted with ❤ by GitHub

Kayıt güncelleme - Update için örnek kodumuz

Öncelikle güncelleme yapılacak kayıt bulunduktan sonra, ilgili entitye ait state bilgisi Modified olarak atanır. Sebebi veri tabanından gelen her bir verinin state bilgisi Unchanged olarak gelir. Güncelleme aşamasında Modified yapılmalıdır.

Örnek kodumuzda personel kaydı güncellemek için personel listesini explicit loading yöntemiyle Collection metodu kullanarak alabiliriz. Bu işlemi yapmazsak null olarak gelir. Yükleme öncesi ve sonrasındaki görünümler aşağıdaki gibidir.


Collection metodu List türündeki navigation propertylerde kullanılır. Listeyi aldıktan sonra güncelleme işlemini yaptıktan sonra SaveChanges metodu ile veri tabanına yansıtma işlemi yapılır.

public void Update()
{
using (var dbContext = new PhoneBookDbContext())
{
//candidate to update
var department = dbContext.Departments.Find(3);
//tracking state of update entity
var item = dbContext.Entry(department);
//change item state to modified
item.State = EntityState.Modified;
//load existing items for one to many collection
item.Collection(i => i.Personals).Load();
//update surname of related data
department.Personals[1].Surname = "Ağaoğlu";
//save change to database
dbContext.SaveChanges();
}
}
view raw Update.cs hosted with ❤ by GitHub

Listeleme için örnek kodumuz 

Güncelleme aşamasında kullandığımız explicit loading yöntemiyle ilişikli personelleri çekebiliriz.

public void ListOfDepartmentWithPersonals()
{
using (var dbContext = new PhoneBookDbContext())
{
//get department without personal list
var department = dbContext.Departments.Find(3);
//After explicit loading to get personal list
dbContext.Entry(department).Collection(i => i.Personals).Load();
}
}
view raw List.cs hosted with ❤ by GitHub

Silme için örnek kodumuz

RemoveRange metodu ile silmek istediğimiz entityi bulup SaveChanges metodu ile veri tabanına yansıtma işlemi yapılır. Böylece ilişkili iki tablodan da verileri siler.

public void DeleteDepartment()
{
using (var dbContext = new PhoneBookDbContext())
{
var department = dbContext.Departments.Find(3);
//Delete to remove both of Department and Personal tables
dbContext.RemoveRange(department);
dbContext.SaveChanges();
}
}
view raw Delete.cs hosted with ❤ by GitHub

Bu yazımda Entity Framework Core'da bire çok ilişkili tablolarla çalışmaktan bahsedip; ilişki kurmanın yanı sıra ekleme, güncelleme, listeleme ve silme işlemine değindim. 

Keyifli ve faydalı olmasını umarak, çalışmalarınızda kolaylıklar diliyorum...

Yorumlar