Aracılığıyla paylaş


EF Core 2.0’daki yeni özellikler

.NET Standard 2.0

EF Core artık .NET Standard 2.0’ı hedeflediğinden .NET Core 2.0, .NET Framework 4.6.1 ile .NET Standard 2.0 uygulayan diğer kitaplıklarla çalışabilir. Desteklenen özellikler hakkında daha fazla bilgi için bkz. Desteklenen .NET Uygulamaları.

Modelleme

Tablo bölme

Artık iki veya daha fazla varlık türü, birincil anahtar sütunlarının paylaşılacağı ve her satırın iki veya daha fazla varlığa karşılık geleceği tek bir tabloyla eşlenebilir.

Tablo bölmeyi kullanmak için tabloyu paylaşan tüm varlık türleri arasında bir tanımlayıcı ilişki (yabancı anahtar özelliklerinin birincil anahtarı oluşturduğu) yapılandırılmalıdır:

modelBuilder.Entity<Product>()
    .HasOne(e => e.Details).WithOne(e => e.Product)
    .HasForeignKey<ProductDetails>(e => e.Id);
modelBuilder.Entity<Product>().ToTable("Products");
modelBuilder.Entity<ProductDetails>().ToTable("Products");

Bu özellik hakkında daha fazla bilgi için tablo bölme bölümünü okuyun.

Sahip olunan türler

Sahip olunan varlık türü, aynı .NET türünü başka bir sahip olunan varlık türüyle paylaşabilir ancak yalnızca .NET türüyle tanımlanamadığı için başka bir varlık türünden ona yönelik bir gezinti olmalıdır. Tanımlama gezintisini içeren varlık, sahip olarak tanımlanır. Sahibi sorgularken sahip olunan türler varsayılan olarak eklenir.

Kural gereği sahip olunan tür için bir gölge birincil anahtar oluşturulur ve tablo bölme kullanılarak sahiple aynı tabloya eşlenir. Bu yaklaşım, sahip olunan türlerin EF6’da kullanıldığı karmaşık türlere benzer şekilde kullanılmasına olanak tanır:

modelBuilder.Entity<Order>().OwnsOne(p => p.OrderDetails, cb =>
    {
        cb.OwnsOne(c => c.BillingAddress);
        cb.OwnsOne(c => c.ShippingAddress);
    });

public class Order
{
    public int Id { get; set; }
    public OrderDetails OrderDetails { get; set; }
}

public class OrderDetails
{
    public StreetAddress BillingAddress { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

public class StreetAddress
{
    public string Street { get; set; }
    public string City { get; set; }
}

Bu özellik hakkında daha fazla bilgi için sahip olunan varlık türleri bölümünü okuyun.

Model düzeyi sorgu filtreleri

EF Core 2.0, model düzeyinde sorgu filtreleri olarak adlandırılan yeni bir özellik içerir. Bu özellik LINQ sorgu koşullarının (genellikle LINQ Where sorgu işlecine geçirilen boole ifadesi) meta veri modelindeki Varlık Türleri üzerinde (genellikle OnModelCreating üzerinde) doğrudan tanımlanmasını sağlar. Bu tür filtreler, Include veya doğrudan gezinti özelliği başvuruları gibi dolaylı olarak başvuruda bulunulan Varlık Türleri de dahil olmak üzere söz konusu Varlık Türlerini içeren tüm LINQ sorgularına otomatik olarak uygulanır. Bu özellikle ilgili bazı yaygın uygulamalar şunlardır:

  • Geçici silme: Varlık Türleri bir IsDeleted özelliği tanımlar.
  • Çok kiracılı: Varlık Türü bir TenantId özelliği tanımlar.

Aşağıda, yukarıda listelenen iki senaryo için özelliği gösteren basit bir örnek verilmiştir:

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    public int TenantId { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>().HasQueryFilter(
            p => !p.IsDeleted
            && p.TenantId == this.TenantId);
    }
}

Post Varlık Türü örnekleri için çok kiracılı ve geçici silme uygulayan model düzeyinde bir filtre tanımladık. DbContext örnek düzeyi özelliğinin kullanımına dikkat edin: TenantId. Model düzeyi filtreleri doğru bağlam örneğindeki değeri (sorguyu yürüten bağlam örneği) kullanır.

IgnoreQueryFilters() işleci kullanılarak filtreler tek LINQ sorguları için devre dışı bırakılabilir.

Sınırlamalar

  • Gezinti başvurularına izin verilmez. Bu özellik geri bildirime göre eklenebilir.
  • Filtreler yalnızca hiyerarşinin kök Varlık Türünde tanımlanabilir.

Veritabanı skaler işlev eşlemesi

EF Core 2.0, LINQ sorgularında kullanılabilmesi ve SQL’e çevrilebilmesi için veritabanı skaler işlevlerini yöntem saptamalarına eşlemeyi sağlayan önemli bir Paul Middleton katkısı içerir.

Aşağıda özelliğin nasıl kullanılacağına dair kısa bir açıklamaya yer verilmiştir:

DbContext üzerinde statik bir yöntem bildirin ve DbFunctionAttribute ile açıklama ekleyin:

public class BloggingContext : DbContext
{
    [DbFunction]
    public static int PostReadCount(int blogId)
    {
        throw new NotImplementedException();
    }
}

Bu tür yöntemler otomatik olarak kaydedilir. Kaydedildikten sonra LINQ sorgusundaki yönteme yapılan çağrılar SQL’deki işlev çağrılarına çevrilebilir:

var query =
    from p in context.Posts
    where BloggingContext.PostReadCount(p.Id) > 5
    select p;

Dikkat edilmesi gereken birkaç nokta:

  • Kural gereği, yöntemin adı SQL oluşturulurken işlevin adı (bu örnekte kullanıcı tanımlı bir işlev) olarak kullanılır ancak yöntem kaydı sırasında adı ve şemayı geçersiz kılabilirsiniz.
  • Şu anda yalnızca skaler işlevler desteklenmektedir.
  • Veritabanında eşlenmiş işlevi oluşturmanız gerekir. EF Core geçişleri bu işlevi oluşturmaz.

Code First için kendi içinde tür yapılandırması

EF6’da EntityTypeConfiguration kaynağından türeterek belirli bir varlık türünün Code First yapılandırmasını kapsüllemek mümkündü. EF Core 2.0’da bu deseni geri getiriyoruz:

class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
    public void Configure(EntityTypeBuilder<Customer> builder)
    {
        builder.HasKey(c => c.AlternateKey);
        builder.Property(c => c.Name).HasMaxLength(200);
    }
}

...
// OnModelCreating
builder.ApplyConfiguration(new CustomerConfiguration());

Yüksek Performans

DbContext havuzu oluşturma

EF Core’un bir ASP.NET Core uygulamasında kullanılmasına yönelik temel desen genellikle özel bir DbContext türünün bağımlılık ekleme sistemine kaydedilmesini ve daha sonra denetleyicilerdeki oluşturucu parametreleri aracılığıyla bu tür örneklerinin elde edilmesini kapsar. Bu, her istek için yeni bir DbContext örneği oluşturulduğu anlamına gelir.

2.0 sürümünde yeniden kullanılabilir DbContext örnekleri havuzunu saydam bir şekilde tanıtan bağımlılık eklemeye özel DbContext türlerini kaydetmenin yeni bir yöntemini sunuyoruz. DbContext havuzu oluşturmayı kullanmak için hizmet kaydı sırasında AddDbContext yerine AddDbContextPool kullanın:

services.AddDbContextPool<BloggingContext>(
    options => options.UseSqlServer(connectionString));

Bu yöntem kullanıldığında bir denetleyici tarafından bir DbContext örneği istendiği sırada önce havuzda kullanılabilir bir örnek olup olmadığı denetlenir. İstek işleme süreci tamamlandıktan sonra örnekteki tüm durumlar sıfırlanır ve örnek havuza döndürülür.

Bu, kavramsal açıdan bağlantı havuzunun ADO.NET sağlayıcılarda çalışma şekline benzerdir ve DbContext örneğinin başlatılmasının bazı maliyetlerinden tasarruf edilmesi avantajına sahiptir.

Sınırlamalar

Yeni yöntem, DbContext OnConfiguring() yönteminde yapılabilecek işlemlere ilişkin birkaç sınırlama getirir.

Uyarı

Türetilmiş DbContext sınıfınızda istekler arasında paylaşılmaması gereken kendi durumunuzu (örneğin, özel alanlar) koruyorsanız DbContext havuzu oluşturmaktan kaçının. EF Core, havuza bir DbContext örneği eklemeden önce yalnızca farkında olduğu durumu sıfırlar.

Açıkça derlenmiş sorgular

Bu, yüksek ölçekli senaryolarda avantaj sunmak için tasarlanmış ikinci katılım performansı özelliğidir.

El ile veya açıkça derlenmiş sorgu API’leri, EF’nin önceki sürümlerinde ve ayrıca uygulamaların sorguların çevirisini önbelleğe alıp yalnızca bir kez hesaplanıp birçok kez yürütülebilmesini sağlamak için LINQ to SQL ile kullanılabilir.

Genel olarak EF Core sorgu ifadelerinin karma gösterimine göre sorguları otomatik olarak derleyebilir ve önbelleğe alabilir. Ancak bu mekanizma karma ve önbellek aramasının hesaplamasını atlayarak küçük bir performans kazancı elde etmek için kullanılabilir ve uygulamanın bir temsilcinin çağrısıyla önceden derlenmiş bir sorgu kullanmasını sağlar.

// Create an explicitly compiled query
private static Func<CustomerContext, int, Customer> _customerById =
    EF.CompileQuery((CustomerContext db, int id) =>
        db.Customers
            .Include(c => c.Address)
            .Single(c => c.Id == id));

// Use the compiled query by invoking it
using (var db = new CustomerContext())
{
   var customer = _customerById(db, 147);
}

Değişiklik İzleme

İliştirme, yeni ve mevcut varlıkların grafiğini izleyebilir

EF Core, çeşitli mekanizmalar aracılığıyla anahtar değerlerinin otomatik olarak oluşturulmasını destekler. Bu özellik kullanılırken anahtar özelliği CLR varsayılan değeriyle (genellikle sıfır veya null) bir değer oluşturulur. Bu, bir varlık grafiğinin DbContext.Attach veya DbSet.Attach noktasına geçirilebileceği ve EF Core’un zaten ayarlanmış bir anahtarı olan varlıkları Unchanged olarak işaretleyeceği ve anahtar kümesi olmayan varlıkların Added olarak işaretleneceği anlamına gelir. Bu, oluşturulan anahtarları kullanırken karma yeni ve mevcut varlıkların grafiğini eklemeyi kolaylaştırır. DbContext.Update ve DbSet.Update anahtar kümesine sahip varlıkların Unchanged yerine Modified olarak işaretlenmesi dışında aynı şekilde çalışır.

Sorgu

Geliştirilmiş LINQ çevirisi

Daha fazla mantığın veritabanında (bellek içi yerine) değerlendirilerek ve veritabanından gereksiz yere daha az veri alınarak daha fazla sorgunun başarıyla yürütülmesini sağlar.

GroupJoin iyileştirmeleri

Bu çalışma, grup birleştirmeleri için oluşturulan SQL kodunu geliştirir. Grup birleştirmeleri genellikle isteğe bağlı gezinti özelliklerindeki alt sorguların sonucu olarak elde edilir.

FromSql ve ExecuteSqlCommand ile dize ilişkilendirme

C# 6, C# ifadelerinin dize değişmez değerlerine doğrudan katıştırılmasını sağlayan ve çalışma zamanında dize oluşturmanın güzel bir yolunu sağlayan Dize İlişkilendirme özelliğini kullanıma sunmuştur. EF Core 2.0’da ham SQL dizelerini kabul eden iki birincil API’mize ilişkilendirilmiş dizeler için özel destek ekledik: FromSql ve ExecuteSqlCommand. Bu yeni destek, C# dize ilişkilendirmenin “güvenli” bir şekilde kullanılmasını sağlar. Bu da çalışma zamanında SQL dinamik olarak oluşturulurken oluşabilecek yaygın SQL ekleme hatalarına karşı koruma sağlar.

Örnek aşağıda verilmiştir:

var city = "London";
var contactTitle = "Sales Representative";

using (var context = CreateContext())
{
    context.Set<Customer>()
        .FromSql($@"
            SELECT *
            FROM ""Customers""
            WHERE ""City"" = {city} AND
                ""ContactTitle"" = {contactTitle}")
            .ToArray();
  }

Bu örnekte SQL biçim dizesine eklenmiş iki değişken vardır. EF Core, aşağıdaki SQL kodunu oluşturur:

@p0='London' (Size = 4000)
@p1='Sales Representative' (Size = 4000)

SELECT *
FROM ""Customers""
WHERE ""City"" = @p0
    AND ""ContactTitle"" = @p1

EF.Functions.Like()

EF Core veya sağlayıcılar tarafından, LINQ sorgularında çağrılabilmeleri için veritabanı işlevlerine veya işleçlerine eşlenen yöntemleri tanımlamak üzere kullanılabilen EF.functions özelliğini ekledik. Böyle bir yöntemin ilk örneği Like():

var aCustomers =
    from c in context.Customers
    where EF.Functions.Like(c.Name, "a%")
    select c;

Like() işlevinin bellek içi bir veritabanında çalışırken veya koşul değerlendirmesinin istemci tarafında gerçekleştirilmesi gerektiğinde kullanışlı olabilecek bellek içi bir uygulamayla birlikte geldiğini unutmayın.

Veritabanı yönetimi

DbContext iskelesi oluşturma için çoğullaştırma kancası

EF Core 2.0, varlık türü adlarını tekilleştirmek ve DbSet adlarını çoğullaştırmak için kullanılan yeni bir IPluralizer hizmeti sunar. Varsayılan uygulama bir işlem değildir, bu nedenle yalnızca kullanıcıların kendi çoğullayıcılarını kolayca takabileceği bir kancadır.

Bir geliştiricinin kendi çoğullayıcısını bağlaması şöyle görünür:

public class MyDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        services.AddSingleton<IPluralizer, MyPluralizer>();
    }
}

public class MyPluralizer : IPluralizer
{
    public string Pluralize(string name)
    {
        return Inflector.Inflector.Pluralize(name) ?? name;
    }

    public string Singularize(string name)
    {
        return Inflector.Inflector.Singularize(name) ?? name;
    }
}

Diğerleri

ADO.NET SQLite sağlayıcısını SQLitePCL.raw’a taşıma

Bu, farklı platformlarda yerel SQLite ikili dosyalarını dağıtmak için Microsoft.Data.Sqlite’ta daha sağlam bir çözüm sunar.

Model başına yalnızca bir sağlayıcı

Sağlayıcıların modelle etkileşim kurma şeklini önemli ölçüde genişletir ve kuralların, ek açıklamaların ve Fluent API’lerin farklı sağlayıcılarla çalışma şeklini basitleştirir.

EF Core 2.0 artık kullanılan her farklı sağlayıcı için farklı bir IModel oluşturur. Bu genellikle uygulama açısından saydamdır. Bu, alt düzey meta veri API’lerinin basitleştirilmesini kolaylaştırmıştır. Böylece yaygın ilişkisel meta veri bağlamlarına erişim her zaman .SqlServer, .Sqlite vb. yerine .Relational çağrısıyla yapılır.

Birleştirilmiş günlüğe kaydetme ve tanılama

Günlüğe kaydetme (ILogger tabanlı) ve tanılama (DiagnosticSource tabanlı) mekanizmaları artık daha fazla kod paylaşıyor.

ILogger’a gönderilen iletilerin olay kimlikleri 2.0’da değişti. Olay kimlikleri artık EF Core kodunda benzersiz. Bu iletiler artık MVC gibi tarafından kullanılan yapılandırılmış günlük kaydı için standart deseni de izliyor.

Günlükçü kategorileri de değişti. Artık DbLoggerCategory aracılığıyla erişilen iyi bilinen bir kategori kümesi var.

DiagnosticSource olayları artık ilgili ILogger iletileriyle aynı olay kimliği adlarını kullanıyor.