Selamlar bu yazımda entityframework core ile veri tabanı bağlantısı ve migration işlemlerini ele alacağız.
Öncelikle projemizi oluşturmamız gerekiyor. Projemizi oluşturmak istediğimiz klasöre gidip şu kodu çalıştıralım
1 |
dotnet new webapi -n MyEfCoreText |
Daha sonrasında projeyi vscode ile açalım
1 |
code ./MyEfCoreText |
Projemiz içerisinde veri tabanında bulunduracağımız tabloları tutmak için bir adet klasör oluşturmamız gerekiyor adına ben Entities diyorum.
İçerisinde bir adet Blog adlı bir class oluşturuyorum
aşağıdaki property’lere sahip bir Blog class’ı oluşturdum
1 2 3 4 5 6 7 8 |
namespace MyEfCoreText.Entities; public class Blog { public int Id { get; set; } public string Url { get; set; } = null!; public string? Title { get; set; } public string Content { get; set; } = string.Empty; } |
Veri tabanımızın bağlantısını yapacak olan ve DbContext sınıfından türetilecek sınıfımızın bulunacağı bir klasör oluşturuyorum adına Persistence dedim. Klasörün içerisinde MyDbContext adlı bir class oluşturdum fakat burada DbContext sınıfını bulamadığını söylüyor arkadaş eklememiz gerekmekte
1 2 3 4 5 6 |
namespace MyEfCoreText.Persistence; public class MyDbContext : DbContext { } |
Projemize bir paket eklememiz gerekiyor bunu iki farklı şekilde yapabiliriz terminal ile ekleyeceğim.
projemizin bulunduğu klasörde aşağıdaki kodu çalıştıralım.
1 |
dotnet add package Microsoft.EntityFrameworkCore |
Bu kod projemize EntityFrameworkCore paketini kuracak, kurduktan sınra MyDbcontext sınıfında en üste using direktif’i eklememiz gerekiyor.
son hali aşağıdaki gibidir.
1 2 3 4 5 6 7 8 |
using Microsoft.EntityFrameworkCore; namespace MyEfCoreText.Persistence; public class MyDbContext : DbContext { } |
Artık burada herhangi bir hata ile karşılaşmayacağız.
Şimdi veri tabanı bağlantımızı yapabilmemiz için iki yol var önce kolay sonra ondan biraz daha zor ama gene kolay olan yolu yapacağız.
DbContext sınıfı direkt olarak veri tabanına bağlantı sağlayamayacağı için bir adet daha paket yüklememiz gerekiyor. Buradaki paket kullandığınız veri tabanı türüne göre değişiklik gösterecek, en çok kullanıldığı için mssql seçiyorum MSSQL kullanıyorsanız aşağıdaki paketi yükleyebilirsiniz.
1 |
dotnet add package Microsoft.EntityFrameworkCore.SqlServer |
Artık mssql server ile bağlantımızı yapabiliriz.
Burada ezbere yaklaşım olmaması adına neden bu adımı yaptığımızı biraz açıklayacağım eğer MyDbContext sınıfı üzerinde kalıtım sağladığımız DbContext sınıfına ctrl+sol tık tuşlarına birlikte basarsanız bu sınıfın içerisine gireceğiz bu sınıfın içerisindeki methodlar içerisinde
OnConfiguring methodu mevcut bu method ile veri tabanımızın yapılandırmasını yapıyoruz en basit olarak bağlantı sağlayacağımız connection string i belirteceğiz bu fonksiyonun virtual olarak işaretlenmesi override yapabileceğimizi söylemekte
sınıfı override yapıp UseSqlServer ile sqlServer bağlantımızı ekliyoruz son hali aşağıdaki şekilde
1 2 3 4 5 6 7 8 9 10 11 |
using Microsoft.EntityFrameworkCore; namespace MyEfCoreText.Persistence; public class MyDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(); } } |
evet burada halen daha bir eksiğimiz mevcut o da sql server bağlantı dizesini vermedik hemen verelim.
eğer imleci fonksiyonun içine getirip ctrl+shift+space tuşuna basarsanız açılan tooltip içerisinde bu fonksiyonun sadece bir string alan overload’ının olduğunu göreceksiniz yani direkt bağlantı metnini verebiliyoruz.
Buradaki bağlantı metni kişinin kullanacağı sql server adresine ve kullanıcı adı ve şifresine göre değişir ben benimkini kullanacağım fakat merak etmeyin sık kullanılan bağlantı dizeleri hakkında ve property’leri hakkında da konuşacağız. Önce MyDbContext sınıfının son halini atayım ve bunun üzerine konuşmaya başlayalım.
1 2 3 4 5 6 7 8 9 10 11 |
using Microsoft.EntityFrameworkCore; namespace MyEfCoreText.Persistence; public class MyDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("Server=.;Database=VeriTabani;User Id=sa; Password=P4$$W0Rd;Trust Server Certificate=true;"); } } |
Burada usqSelServer içerisinde vermiş olduğum string ifadeler için konuşuyorum
- Server değeri sunucunuzun bulunduğu adrestir benim kullandığım . ifadesinin anlamı localhost’dur yani 127.0.0.1 veya localhot veya . ifadesini kullanabilirsiniz eğer sunucu kendi bilgisayarınızda kurulu ise. Eğer aynı network’e sahip başka bir bilgisayarda kurulu ise o bilgisayarın ipAdresini vermeniz gerekmekte örn: 192.168.1.45 eğer uzaktaki bir sunucuda ise domain adını veya ip adresini verebilirsiniz. Örneğin; 145.45.78.54 veya db.erdincyasan.com şeklinde
- Database ifadesi MyDbContext ifadesi sunucuda hangi veri tabanını temsil ediyoru onu yazalım içerisinde direkt olarak VeriTabani yazdim yani benim veri tabanimin ismi VeriTabani olacak =)
- User Id değeri veri tabanına bağlanırken kullanacağımız kullanıcı adı
- Password değeri de User Id içerisinde belirttiğiniz kullanıcının şifresi
- Trust Server Certificate Nedendir bilmiyorum ama mssql sunucusunu docker container içerisinde çalıştırırken sertifika uyumsuzluğu sorunu yaşıyorum bu değeri sunucunun sertifikasına güven anlamında ekledim ve çalışıyor
Şimdi bir de olası bir diğer connection string’ine bakalım
1 |
optionsBuilder.UseSqlServer("Server=localhosT:Database=VeriTabani;Integrated Security=true;"); |
Eğer mssql sunucunuz programın çalıştığı bilgisayar üzerine kurulu ise Integrated Security ifadesini true olarak setlerseniz şifre vermeye gerek kalmıyor sonrasındaki bütün işlemler windows’un kendi şifreleme sistemiyle çalışıyor fakat unutmayın uzaktaki sunuculara bu şekilde bağlanamazsınız!
Not: Ben ilk attığım connection string’ini kullanarak devam ediyorum.
Teknik olarak her şeyi hazırladık şimdi webapi içerisinde bu dbContext’i kullanmaya geldi bunun için servislerimize dbContext’i eklememiz gerekiyor hemen Program.cs dosyasına gidiyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using MyEfCoreText.Persistence; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddDbContext<MyDbContext>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); |
builder.Build() demeden önce dbContext’imi ekledim bu artık bu dbContext’i kullanabileceğim anlamına geliyor hemen deneyelim, öncelikle bir TestController oluşturalım ve burada DbContext değerini kullanmaya çalışalım.
controller oluşturmadan önce veri tabanındaki tablomuzu da MyDbContext içerisine eklememiz gerekiyor şu şekilde güncelleyelim
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using Microsoft.EntityFrameworkCore; using MyEfCoreText.Entities; namespace MyEfCoreText.Persistence; public class MyDbContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("Server=.;Database=VeriTabani;User Id=sa; Password=P4$$W0Rd;Trust Server Certificate=true;"); } } |
8. satırı ekledim böylelikle veri tabanı üzerindeki tabloma erişebileceğim.
TestController oluşturdum o da aşağıdaki şekilde,
Controllers klasörü altında oluşturmanızı tavsiye ederim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using Microsoft.AspNetCore.Mvc; using MyEfCoreText.Persistence; namespace MyEfCoreText.Controllers; [ApiController] [Route("[controller]")] public class TestController : ControllerBase { public IActionResult Get() { var dbContext = new MyDbContext(); var blogs = dbContext.Blogs.ToList(); return Ok(); } } |
burada işaretlediğim satıra gelindiğinde veri tabanı üzerinde bulunan tüm blog içeriklerini çekmesi gerekiyor hadi deneyelim.
Evet projeyi çalıştırdığımda Swagger üzerinde bir hata ile karşılaştım:
Bunun sebebi oluşturduğumuz controller içerisindeki methodun hangi http method’una denk geldiğini anlamamasıdır routing’i zaten controller üstünde belirttik fakat bu sadece path’i belirler sonrasında bu class’ın altında birden fazla method var mı yok mu bilemez bundan ötürü şu satırı eklememiz gerekiyor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using Microsoft.AspNetCore.Mvc; using MyEfCoreText.Persistence; namespace MyEfCoreText.Controllers; [ApiController] [Route("[controller]")] public class TestController : ControllerBase { [HttpGet] public IActionResult Get() { var dbContext = new MyDbContext(); var blogs = dbContext.Blogs.ToList(); return Ok(); } } |
Artık bir problem olmayacak.
Tamam şimdi siz burada methodu denemeye çalıştığınızda bir süre bekledikten sonra hata fırlatacaktır, hatanın sebebi : veri tabanına bağlanamaması, beklemesinin sebebi : Birden fazla kes bağlanmaya çalışması
Biz veri tabanını c# tarafında oluşturduk fakat veri tabanı sunucumuzda veri tabanını oluşturmadık bunu oluşturmamız için Migrations işlemlerine geçmemiz lazım. Fakat o da sonranın konusu şimdilik veri tabanına bağlanmak için iki adet yol var demiştim şimdi diğer methoda bakalım.
Önceki methodda veri tabanına bağlantı yaparken DbContext içerisindeki OnConfiguring methodunu kullandık, bu methodda ise veritabanı ayarlarını Constructor içerisinde alacağız
Eğer dbContext sınıfı içerisine tekrardan ctrl+sol tık ile gidersek bir constructor’ı olduğunu göreceğiz
Biz buradaki constructor’ı kullanarak dbContextOptions’ını geçebiliriz zaten bizim OnConfiguring methodumuz parametre olarak ne alıyordu hatırlayalım
eğer onConfiguring methodu içerisindeki DbContextOptionsbuilder class’ı içerisine gidersek şunu görebilmemiz çok açık
Gördüğünüz gibi optionsBuilder DbContextOptions’ı build etmek için kullanılıyor
Yani Eğer constructor içerisinde DbContextOptions’ı elimizle verirsek onu kullanacak demek oluyor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
using Microsoft.EntityFrameworkCore; using MyEfCoreText.Entities; namespace MyEfCoreText.Persistence; public class MyDbContext : DbContext { public DbSet<Blog> Blogs { get; set; } public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { } } |
DbContext sınıfımızdaki constructor’ı değiştirdik artık veri tabanı bağlantımızı direkt olarak contructor oluşturulurken verebiliriz eğer bağlantımızı bu şekilde yapmak istiyorsak veri tabanımızı Program.cs içerisinde başka bir şekilde eklememiz gerekiyor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using Microsoft.EntityFrameworkCore; using MyEfCoreText.Persistence; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // builder.Services.AddDbContext<MyDbContext>(); builder.Services.AddDbContext<MyDbContext>( options => { options.UseSqlServer(builder.Configuration.GetConnectionString("Server=.;Database=VeriTabani;User Id=sa; Password=P4$$W0Rd;Trust Server Certificate=true;")); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); |
Evet 13. satırı yorum satırına aldım çünkü artık ona ihtiyacım yok, gördüğünüz gibi 14. satırda veri tabanımızı gene ekliyorum fakat bu sefer ayarlarını bir action delege ile yapıyorum aslında onConfiguring içerisinde yaptığımız şeyin aynısı
Veri tabanı Context’imizi bu şekilde eklediğimizde TestController içerisinde artık DbContext’imizi bu şekilde kullanamadığımızı görüyoruz
Çünkü artık parametre almadan dbContext’i oluşturacak bir yapımız yok bundan dolayı hata almaktayız. Fakat üzülmeyin bunun yerine Constructor içerisinde veya fromServices şeklinde DbContext’imizi alabiliriz!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using Microsoft.AspNetCore.Mvc; using MyEfCoreText.Persistence; namespace MyEfCoreText.Controllers; [ApiController] [Route("[controller]")] public class TestController : ControllerBase { private readonly MyDbContext _context; public TestController(MyDbContext context) { _context = context; } [HttpGet] public IActionResult Get() { var blogs = _context.Blogs.ToList(); return Ok(); } } |
Bu method ile alabilmemizin sebebi aslında Dependency Injection yapabilmemizdir şimdi eğer programı tekrar başlattığımızda veri tabanı bağlantı hatası dışında bir hata almazsak işlemimiz başarılı demektir.
Siz istek attığınız süreye kadar DbContext değeri bağlanmaya çalışmayacağı için hata almazsınız fakat eğer tekrardan get isteğini denersek
Evet çalıştırdığımda bir hata aldım aldığım hatanın sebebi connection string’i set ederken yanlış set etmişiz configuration üzerinden almak yerine direkt olarak string değerini vermemiz gerekiyordu Program.cs içerisini şu şekilde güncelledim. 17. satırı 18. satır haline getirelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
using Microsoft.EntityFrameworkCore; using MyEfCoreText.Persistence; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // builder.Services.AddDbContext<MyDbContext>(); builder.Services.AddDbContext<MyDbContext>( options => { // options.UseSqlServer(builder.Configuration.GetConnectionString("Server=.;Database=VeriTabani;User Id=sa; Password=P4$$W0Rd;Trust Server Certificate=true;")); options.UseSqlServer("Server=.;Database=VeriTabani;User Id=sa; Password=P4$$W0Rd;Trust Server Certificate=true;"); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); |
Tekrar denediğimizde herhangi bir problem yok yani aslında var da beklemediğimiz bişey değil 😀
Sonraki yazıda migration oluşturma ve veri tabanını güncelleme işlemi yaparak db context üzerinde işlemler yapmaya devam edebiliriz.
Bu yazıyı yazma amacımı açıklama gereği hissettim çünkü hatalı bir şekilde bırakıyorum: Bu yazıyı aslında zaten DbContext bağlantısını yapan fakat bazı yerlerinde hata alan ve bu dbContext bağlantısının derinlemesine nasıl çalıştığını bilmek isteyenler için yazdım. Eğer sıfırdan öğreniyorsanız zaten sonraki yazılar bu yazının devamı olacağı için oradan devam ederek veri tabanı bağlantınızı sağlayabilirsiniz.
Herkese iyi çalışmalar.