Fitur baru di EF Core 2.0
.NET Standar 2.0
EF Core sekarang menargetkan .NET Standard 2.0, yang berarti dapat bekerja dengan .NET Core 2.0, .NET Framework 4.6.1, dan pustaka lain yang mengimplementasikan .NET Standard 2.0. Lihat Implementasi .NET yang didukung untuk detail selengkapnya tentang apa yang didukung.
Pemodelan
Pemisahan tabel
Sekarang dimungkinkan untuk memetakan dua atau lebih jenis entitas ke tabel yang sama di mana kolom kunci utama akan dibagikan dan setiap baris akan sesuai dengan dua entitas atau lebih.
Untuk menggunakan tabel yang memisahkan hubungan identifikasi (di mana properti kunci asing membentuk kunci primer) harus dikonfigurasi antara semua jenis entitas yang berbagi tabel:
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");
Baca bagian tentang pemisahan tabel untuk informasi selengkapnya tentang fitur ini.
Jenis yang dimiliki
Jenis entitas yang dimiliki dapat berbagi jenis .NET yang sama dengan jenis entitas milik lain, tetapi karena tidak dapat diidentifikasi hanya dengan jenis .NET harus ada navigasi ke sana dari jenis entitas lain. Entitas yang berisi navigasi yang menentukan adalah pemiliknya. Saat mengkueri pemilik jenis yang dimiliki akan disertakan secara default.
Menurut konvensi, kunci primer bayangan akan dibuat untuk jenis yang dimiliki dan akan dipetakan ke tabel yang sama dengan pemilik dengan menggunakan pemisahan tabel. Ini memungkinkan untuk menggunakan jenis yang dimiliki mirip dengan bagaimana jenis kompleks digunakan dalam EF6:
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; }
}
Baca bagian pada jenis entitas yang dimiliki untuk informasi selengkapnya tentang fitur ini.
Filter kueri tingkat model
EF Core 2.0 menyertakan fitur baru yang kami sebut filter kueri tingkat Model. Fitur ini memungkinkan predikat kueri LINQ (ekspresi boolean biasanya diteruskan ke LINQ Di mana operator kueri) ditentukan langsung pada Jenis Entitas dalam model metadata (biasanya dalam OnModelCreating). Filter tersebut secara otomatis diterapkan ke kueri LINQ apa pun yang melibatkan Jenis Entitas tersebut, termasuk Jenis Entitas yang direferensikan secara tidak langsung, seperti melalui penggunaan referensi properti Sertakan atau navigasi langsung. Beberapa aplikasi umum dari fitur ini adalah:
- Penghapusan sementara - Jenis Entitas mendefinisikan properti IsDeleted.
- Multi-penyewaan - Jenis Entitas menentukan properti TenantId.
Berikut adalah contoh sederhana yang menunjukkan fitur untuk dua skenario yang tercantum di atas:
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);
}
}
Kami mendefinisikan filter tingkat model yang mengimplementasikan multi-penyewaan dan penghapusan sementara untuk instans Post Jenis Entitas. Perhatikan penggunaan DbContext properti tingkat instans: TenantId. Filter tingkat model akan menggunakan nilai dari instans konteks yang benar (yaitu, instans konteks yang menjalankan kueri).
Filter dapat dinonaktifkan untuk kueri LINQ individual menggunakan operator IgnoreQueryFilters().
Batasan
- Referensi navigasi tidak diperbolehkan. Fitur ini dapat ditambahkan berdasarkan umpan balik.
- Filter hanya dapat ditentukan pada Jenis Entitas akar hierarki.
Pemetaan fungsi skalar database
EF Core 2.0 mencakup kontribusi penting dari Paul Middleton yang memungkinkan pemetaan fungsi skalar database ke tikungan metode sehingga dapat digunakan dalam kueri LINQ dan diterjemahkan ke SQL.
Berikut adalah deskripsi singkat tentang bagaimana fitur tersebut dapat digunakan:
Deklarasikan metode statis pada Anda DbContext dan anotasi dengan DbFunctionAttribute:
public class BloggingContext : DbContext
{
[DbFunction]
public static int PostReadCount(int blogId)
{
throw new NotImplementedException();
}
}
Metode seperti ini secara otomatis terdaftar. Setelah terdaftar, panggilan ke metode dalam kueri LINQ dapat diterjemahkan ke panggilan fungsi di SQL:
var query =
from p in context.Posts
where BloggingContext.PostReadCount(p.Id) > 5
select p;
Beberapa hal yang perlu diperhatikan:
- Menurut konvensi, nama metode digunakan sebagai nama fungsi (dalam hal ini fungsi yang ditentukan pengguna) saat menghasilkan SQL, tetapi Anda dapat mengganti nama dan skema selama pendaftaran metode.
- Saat ini hanya fungsi skalar yang didukung.
- Anda harus membuat fungsi yang dipetakan dalam database. Migrasi EF Core tidak akan mengurus pembuatannya.
Konfigurasi jenis mandiri untuk kode terlebih dahulu
Di EF6 dimungkinkan untuk merangkum konfigurasi pertama kode dari jenis entitas tertentu dengan berasal dari EntityTypeConfiguration. Di EF Core 2.0 kami mengembalikan pola ini:
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());
Performa Tinggi
Pengumpulan DbContext
Pola dasar untuk menggunakan EF Core dalam aplikasi ASP.NET Core biasanya melibatkan pendaftaran jenis DbContext kustom ke dalam sistem injeksi dependensi dan kemudian mendapatkan instans jenis tersebut melalui parameter konstruktor di pengontrol. Ini berarti instans baru DbContext dibuat untuk setiap permintaan.
Dalam versi 2.0, kami memperkenalkan cara baru untuk mendaftarkan jenis DbContext kustom dalam injeksi dependensi yang secara transparan memperkenalkan kumpulan instans DbContext yang dapat digunakan kembali. Untuk menggunakan pengumpulan DbContext, gunakan alih-alih AddDbContextPoolAddDbContext selama pendaftaran layanan:
services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(connectionString));
Jika metode ini digunakan, pada saat instans DbContext diminta oleh pengontrol, pertama-tama kita akan memeriksa apakah ada instans yang tersedia di kumpulan. Setelah pemrosesan permintaan selesai, status apa pun pada instans diatur ulang dan instans itu sendiri dikembalikan ke kumpulan.
Ini secara konseptual mirip dengan bagaimana pengumpulan koneksi beroperasi di penyedia ADO.NET dan memiliki keuntungan menghemat beberapa biaya inisialisasi instans DbContext.
Batasan
Metode baru memperkenalkan beberapa batasan tentang apa yang dapat dilakukan dalam OnConfiguring() metode DbContext.
Peringatan
Hindari menggunakan Pengumpulan DbContext jika Anda mempertahankan status Anda sendiri (misalnya, bidang privat) di kelas DbContext turunan Anda yang tidak boleh dibagikan di seluruh permintaan. EF Core hanya akan mengatur ulang status yang diketahui sebelum menambahkan instans DbContext ke kumpulan.
Kueri yang dikompilasi secara eksplisit
Ini adalah fitur performa keikutsertaan kedua yang dirancang untuk menawarkan manfaat dalam skenario skala tinggi.
API kueri yang dikompilasi secara manual atau eksplisit telah tersedia di versi EF sebelumnya dan juga di LINQ untuk SQL memungkinkan aplikasi menyimpan terjemahan kueri sehingga hanya dapat dihitung sekali dan dijalankan berkali-kali.
Meskipun secara umum EF Core dapat secara otomatis mengkompilasi dan menyimpan kueri berdasarkan representasi hash ekspresi kueri, mekanisme ini dapat digunakan untuk mendapatkan perolehan performa kecil dengan melewati komputasi hash dan pencarian cache, memungkinkan aplikasi untuk menggunakan kueri yang sudah dikompilasi melalui pemanggilan delegasi.
// 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);
}
Pelacakan Perubahan
Lampirkan dapat melacak grafik entitas baru dan yang sudah ada
EF Core mendukung pembuatan otomatis nilai kunci melalui berbagai mekanisme. Saat menggunakan fitur ini, nilai dihasilkan jika properti kunci adalah default CLR--biasanya nol atau null. Ini berarti bahwa grafik entitas dapat diteruskan ke DbContext.Attach atau DbSet.Attach dan EF Core akan menandai entitas yang memiliki kunci yang sudah ditetapkan sebagai Unchanged sementara entitas yang tidak memiliki set kunci akan ditandai sebagai Added. Ini memudahkan untuk melampirkan grafik entitas baru campuran dan yang sudah ada saat menggunakan kunci yang dihasilkan. DbContext.Update dan DbSet.Update bekerja dengan cara yang sama, kecuali bahwa entitas dengan set kunci ditandai sebagai Modified bukan Unchanged.
Kueri
Terjemahan LINQ yang disempurnakan
Memungkinkan lebih banyak kueri untuk berhasil dijalankan, dengan lebih banyak logika yang dievaluasi dalam database (bukan dalam memori) dan lebih sedikit data yang tidak perlu diambil dari database.
Penyempurnaan GroupJoin
Pekerjaan ini meningkatkan SQL yang dihasilkan untuk gabungan grup. Gabungan grup paling sering merupakan hasil dari subkueri pada properti navigasi opsional.
Interpolasi string di FromSql dan ExecuteSqlCommand
C# 6 memperkenalkan Interpolasi String, fitur yang memungkinkan ekspresi C# secara langsung disematkan dalam literal string, menyediakan cara yang bagus untuk membangun string pada waktu proses. Dalam EF Core 2.0 kami menambahkan dukungan khusus untuk string terinterpolasi ke dua API utama kami yang menerima string SQL mentah: FromSql dan ExecuteSqlCommand. Dukungan baru ini memungkinkan interpolasi string C# digunakan dengan cara "aman". Artinya, dengan cara yang melindungi dari kesalahan umum SQL injeksi yang dapat terjadi ketika membangun SQL secara dinamis pada runtime.
Berikut contohnya:
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();
}
Dalam contoh ini, ada dua variabel yang disematkan dalam string format SQL. EF Core akan menghasilkan SQL berikut:
@p0='London' (Size = 4000)
@p1='Sales Representative' (Size = 4000)
SELECT *
FROM ""Customers""
WHERE ""City"" = @p0
AND ""ContactTitle"" = @p1
EF. Functions.Like()
Kami telah menambahkan EF. Properti Functions yang dapat digunakan oleh EF Core atau penyedia untuk menentukan metode yang memetakan ke fungsi atau operator database sehingga dapat dipanggil dalam kueri LINQ. Contoh pertama dari metode tersebut adalah Like():
var aCustomers =
from c in context.Customers
where EF.Functions.Like(c.Name, "a%")
select c;
Perhatikan bahwa Like() dilengkapi dengan implementasi dalam memori, yang dapat berguna saat bekerja melawan database dalam memori atau ketika evaluasi predikat perlu terjadi di sisi klien.
Pengelolaan database
Kait pluralisasi untuk perancah DbContext
EF Core 2.0 memperkenalkan layanan IPluralizer baru yang digunakan untuk mensingkularisasi nama jenis entitas dan mengharuskan nama DbSet. Implementasi default adalah no-op, jadi ini hanyalah kait di mana orang-orang dapat dengan mudah mencolokkan pluralizer mereka sendiri.
Berikut adalah tampilannya bagi pengembang untuk mengaitkan pluralizer mereka sendiri:
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;
}
}
Lainnya
Pindahkan penyedia SQLite ADO.NET ke SQLitePCL.raw
Ini memberi kami solusi yang lebih kuat di Microsoft.Data.Sqlite untuk mendistribusikan biner SQLite asli di platform yang berbeda.
Hanya satu penyedia per model
Secara signifikan menambah bagaimana penyedia dapat berinteraksi dengan model dan menyederhanakan bagaimana konvensi, anotasi, dan API fasih bekerja dengan penyedia yang berbeda.
EF Core 2.0 sekarang akan membangun IModel yang berbeda untuk setiap penyedia berbeda yang digunakan. Ini biasanya transparan untuk aplikasi. Ini telah memfasilitasi penyederhanaan API metadata tingkat bawah sehingga akses apa pun ke konsep metadata relasional umum selalu dilakukan melalui panggilan ke .Relational alih-alih .SqlServer, , .Sqlitedll.
Pengelogan dan diagnostik terkonsolidasi
Pengelogan (berdasarkan ILogger) dan Diagnostik (berdasarkan mekanisme DiagnosticSource) sekarang berbagi lebih banyak kode.
ID peristiwa untuk pesan yang dikirim ke ILogger telah berubah di 2.0. ID peristiwa sekarang unik di seluruh kode EF Core. Pesan-pesan ini sekarang juga mengikuti pola standar untuk pengelogan terstruktur yang digunakan oleh, misalnya, MVC.
Kategori pencatat juga telah berubah. Sekarang ada serangkaian kategori terkenal yang diakses melalui DbLoggerCategory.
Peristiwa diagnosticSource sekarang menggunakan nama ID peristiwa yang sama dengan pesan terkait ILogger .