ABP Framework ile Adım Adım Yazılım Geliştirme – Bölüm 3: Veri Modeli Oluşturma
Her uygulamanın temelinde bir veri modeli bulunur. ABP Framework, veri modelinizi tanımlamanız ve veritabanıyla etkileşim kurmanız için güçlü araçlar ve prensipler sunar. Bu bölümde, entity’ler oluşturmaktan veritabanı migrasyonlarına kadar olan süreci adım adım inceleyeceğiz.
Entity Kavramı ve Entity Oluşturma
Entity (Varlık), uygulamanızın iş dünyasındaki benzersiz bir nesneyi temsil eden bir sınıftır. Her entity’nin benzersiz bir kimliği (Id) vardır ve yaşam döngüsü boyunca durumu değişebilir. ABP Framework’te bir sınıfı entity olarak tanımlamak için Volo.Abp.Domain.Entities.Entity<TKey>
sınıfından türetilir.
Örnek bir Book
entity’si:
C#
using System;
using Volo.Abp.Domain.Entities;
namespace MyProject.Books
{
public class Book : Entity<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
// Ek özellikler
}
public enum BookType
{
Undefined,
Adventure,
ScienceFiction,
Fantasy,
Horror
}
}
Aggregate Root ve IEntity Interface’i
Aggregate Root, DDD’de bir dizi ilgili nesnenin (entity’ler ve değer nesneleri) tutarlılığını sağlayan ana entity’dir. Bir aggregate root’un dışarıdan erişilebilen tek public varlığı kendisidir; içerideki diğer entity’lere ve değer nesnelerine doğrudan erişim engellenir.
ABP’de bir entity’yi aggregate root olarak işaretlemek için Volo.Abp.Domain.Entities.AggregateRoot<TKey>
sınıfından türetilir:
C#
using Volo.Abp.Domain.Entities;
namespace MyProject.Books
{
public class Book : AggregateRoot<Guid> // Artık bir Aggregate Root
{
public string Name { get; set; }
// ... diğer özellikler
}
}
IEntity
interface’i, bir nesnenin bir entity olduğunu ve bir kimliğe sahip olduğunu belirten temel bir arayüzdür. Entity
ve AggregateRoot
sınıfları bu arayüzü zaten implemente eder.
Entity Özellikleri ve Varsayılan Alanlar (Id, CreationTime, vb.)
ABP Framework, entity’ler için birçok faydalı varsayılan özellik sunar. Bu özellikler, belirli arayüzleri implemente ederek entity’lerinize otomatik olarak eklenebilir:
Id
:Entity<TKey>
veyaAggregateRoot<TKey>
kullanılarak otomatik olarak eklenir. GenellikleGuid
veyaint
tipindedir.ICreationAudited
:CreationTime
veCreatorId
alanlarını ekler. Bir kayıt oluşturulduğunda otomatik olarak doldurulur.IModificationAudited
:LastModificationTime
veLastModifierId
alanlarını ekler. Bir kayıt güncellendiğinde otomatik olarak doldurulur.IDeletionAudited
:IsDeleted
,DeletionTime
veDeleterId
alanlarını ekler. “Soft delete” (yumuşak silme) özelliği için kullanılır.IVersionedEntity
:ExtraProperties
veConcurrencyStamp
gibi alanlar ekleyerek eşzamanlılık kontrolü sağlar.
Örnek: Denetlenebilir bir Book
entity’si:
C#
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace MyProject.Books
{
public class Book : FullAuditedAggregateRoot<Guid> // Hem yaratma, hem değiştirme, hem de silme denetimi
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
EF Core Entegrasyonu ve DbContext Yapılandırması
ABP Framework, veritabanı etkileşimi için varsayılan olarak Entity Framework Core (EF Core) kullanır. YourProjectName.EntityFrameworkCore
projesinde bulunan YourProjectNameDbContext
sınıfı, uygulamanızın veritabanı bağlamını temsil eder.
Bu sınıf, AbpDbContext<YourProjectNameDbContext>
sınıfından türetilir ve DbSet
özellikleri aracılığıyla entity’lerinizi veritabanı tablolarına eşleştirirsiniz:
C#
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using MyProject.Books;
[ConnectionStringName("Default")]
public class MyProjectDbContext : AbpDbContext<MyProjectDbContext>
{
public DbSet<Book> Books { get; set; }
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Configure your own tables/entities inside here */
builder.Entity<Book>(b =>
{
b.ToTable(MyProjectConsts.DbTablePrefix + "Books",
MyProjectConsts.DbSchema);
b.ConfigureByConvention(); // Auto configure for the base properties
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
}
}
OnModelCreating
metodu, entity’lerinizin veritabanı tablolarına nasıl eşleştirileceğini (tablo adı, kolon adları, kısıtlamalar vb.) yapılandırmanıza olanak tanır. ConfigureByConvention()
ABP’nin varsayılan mapping kurallarını uygulamasını sağlar.
Code First Yaklaşımı ile Migration Oluşturma
ABP Framework, EF Core’un Code First yaklaşımını ve Migrations özelliğini kullanarak veritabanı şemanızı kodunuzdan yönetmenizi sağlar.
- Migration Ekleme: Entity’lerinizde veya DbContext’inizde değişiklik yaptığınızda, Package Manager Console (PMC) veya komut satırı (CLI) üzerinden yeni bir migration oluşturursunuz:
- PMC:
Add-Migration "Added_Books_Table"
(TodoApp.EntityFrameworkCore projesini seçtiğinizden emin olun) - CLI:
dotnet ef migrations add "Added_Books_Table" -p src/TodoApp.EntityFrameworkCore
- PMC:
- Bu komut, veritabanı şemasında yapılan değişiklikleri tanımlayan bir C# dosyası oluşturur.
Veritabanı Şemasını Güncelleme
Migration dosyası oluşturulduktan sonra, bu migration’ı veritabanınıza uygulamalısınız:
- PMC:
Update-Database
(TodoApp.EntityFrameworkCore projesini seçtiğinizden emin olun) - CLI:
dotnet ef database update -p src/TodoApp.EntityFrameworkCore
ABP projelerinde genellikle YourProjectName.DbMigrator
adında ayrı bir proje bulunur. Bu proje, uygulamanızın ilk başlangıcında veya manuel olarak çalıştırılarak veritabanı migrasyonlarını otomatik olarak uygulamanıza ve başlangıç verilerini (seed data) eklemenize olanak tanır.
Seed Data Oluşturma
Uygulamanızın ilk çalışmasında veya belirli senaryolar için varsayılan veriler oluşturmak isteyebilirsiniz (örn. yönetici kullanıcısı, temel roller, başlangıç kategorileri). Buna Seed Data denir.
ABP’de seed data oluşturmak için IDataSeeder
interface’ini implemente eden servisler kullanabilirsiniz. Bu servisler, YourProjectNameDbMigrationModule
veya benzeri bir modül içerisinde çağrılarak veritabanı başlatılırken çalıştırılır.
Örnek bir BookStoreDataSeeder
sınıfı:
C#
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using MyProject.Books;
namespace MyProject
{
public class MyProjectDataSeeder : IDataSeeder, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
public MyProjectDataSeeder(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() <= 0)
{
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1979, 10, 12),
Price = 42.0f
},
autoSave: true
);
}
}
}
}
Bu bölüm, veri modelinizi oluşturma ve veritabanı etkileşimini yönetme sürecini kapsamaktadır. Sonraki bölümde, domain katmanınızı nasıl geliştireceğinizi öğreneceğiz.