Bagikan melalui


Perubahan mencolok disertakan dalam EF Core 3.x

PERUBAHAN API dan perilaku berikut berpotensi memutus aplikasi yang ada saat meningkatkannya menjadi 3.x. Perubahan yang kami harapkan hanya berdampak pada penyedia database didokumenkan di bawah perubahan penyedia.

Ringkasan

Perubahan mencolok Dampak
Kueri LINQ tidak lagi dievaluasi pada klien Sangat Penting
Alat baris perintah EF Core, dotnet ef, bukan lagi bagian dari .NET Core SDK Sangat Penting
DetectChanges menghormati nilai kunci yang dihasilkan penyimpanan Sangat Penting
FromSql, ExecuteSql, dan ExecuteSqlAsync telah diganti namanya Sangat Penting
Jenis kueri dikonsolidasikan dengan jenis entitas Sangat Penting
Entity Framework Core tidak lagi menjadi bagian dari kerangka kerja bersama ASP.NET Core Medium
Penghapusan kaskade sekarang terjadi segera secara default Medium
Pemuatan entitas terkait yang bersemangat sekarang terjadi dalam satu kueri Medium
DeleteBehavior.Restrict memiliki semantik yang lebih bersih Medium
API Konfigurasi untuk hubungan jenis yang dimiliki telah berubah Medium
Setiap properti menggunakan pembuatan kunci bilangan bulat dalam memori independen Medium
Kueri tanpa pelacakan tidak lagi melakukan resolusi identitas Medium
Perubahan API metadata Medium
Perubahan API Metadata khusus penyedia Medium
UseRowNumberForPaging telah dihapus Medium
Metode FromSql saat digunakan dengan prosedur tersimpan tidak dapat disusur Medium
Metode FromSql hanya dapat ditentukan pada akar kueri Kurang Penting
Nilai kunci sementara tidak lagi diatur ke instans entitas Kurang Penting
Entitas dependen yang berbagi tabel dengan prinsipal sekarang bersifat opsional Kurang Penting
Semua entitas yang berbagi tabel dengan kolom token konkurensi harus memetakannya ke properti Kurang Penting
Entitas yang dimiliki tidak dapat dikueri tanpa pemilik menggunakan kueri pelacakan Kurang Penting
Properti yang diwariskan dari jenis yang tidak dipetakan sekarang dipetakan ke satu kolom untuk semua jenis turunan Kurang Penting
Konvensi properti kunci asing tidak lagi cocok dengan nama yang sama dengan properti utama Kurang Penting
Koneksi database sekarang ditutup jika tidak digunakan lagi sebelum TransactionScope selesai Kurang Penting
Bidang penolakan digunakan secara default Kurang Penting
Lempar jika beberapa bidang backing yang kompatibel ditemukan Kurang Penting
Nama properti bidang saja harus cocok dengan nama bidang Kurang Penting
AddDbContext/AddDbContextPool tidak lagi memanggil AddLogging dan AddMemoryCache Kurang Penting
AddEntityFramework* menambahkan IMemoryCache dengan batas ukuran Kurang Penting
DbContext.Entry sekarang melakukan DetectChanges lokal Kurang Penting
Kunci array string dan byte tidak dihasilkan klien secara default Kurang Penting
ILoggerFactory sekarang menjadi layanan terlingkup Kurang Penting
Proksi pemuatan malas tidak lagi mengasumsikan properti navigasi dimuat sepenuhnya Kurang Penting
Pembuatan penyedia layanan internal yang berlebihan sekarang menjadi kesalahan secara default Kurang Penting
Perilaku baru untuk HasOne/HasMany dipanggil dengan satu string Kurang Penting
Jenis pengembalian untuk beberapa metode asinkron telah diubah dari Tugas ke ValueTask Kurang Penting
Anotasi Relational:TypeMapping sekarang hanya TypeMapping Kurang Penting
ToTable pada jenis turunan melempar pengecualian Kurang Penting
EF Core tidak lagi mengirim pragma untuk penegakan SQLite FK Kurang Penting
Microsoft.EntityFrameworkCore.Sqlite sekarang bergantung pada SQLitePCLRaw.bundle_e_sqlite3 Kurang Penting
Nilai guid sekarang disimpan sebagai TEXT di SQLite Kurang Penting
Nilai karakter sekarang disimpan sebagai TEKS di SQLite Kurang Penting
ID migrasi sekarang dihasilkan menggunakan kalender budaya invariant Kurang Penting
Info/metadata ekstensi telah dihapus dari IDbContextOptionsExtension Kurang Penting
LogQueryPossibleExceptionWithAggregateOperator telah diganti namanya Kurang Penting
Mengklarifikasi API untuk nama batasan kunci asing Kurang Penting
IRelationalDatabaseCreator.HasTables/HasTablesAsync telah dipublikasikan Kurang Penting
Microsoft.EntityFrameworkCore.Design sekarang menjadi paket DevelopmentDependency Kurang Penting
SQLitePCL.raw diperbarui ke versi 2.0.0 Kurang Penting
NetTopologySuite diperbarui ke versi 2.0.0 Kurang Penting
Microsoft.Data.SqlClient digunakan alih-alih System.Data.SqlClient Kurang Penting
Beberapa hubungan referensi mandiri ambigu harus dikonfigurasi Kurang Penting
DbFunction.Schema menjadi string null atau kosong mengonfigurasinya agar berada dalam skema default model Kurang Penting
EF Core 3.0 menargetkan .NET Standard 2.1 daripada .NET Standard 2.0 Reverted
Eksekusi kueri dicatat di tingkat Debug Dikembalikan

Perubahan berdampak tinggi

Kueri LINQ tidak lagi dievaluasi pada klien

Masalah Pelacakan #14935Lihat juga masalah #12795

Perilaku yang lama

Sebelum 3.0, ketika EF Core tidak dapat mengonversi ekspresi yang merupakan bagian dari kueri ke SQL atau parameter, EF Core secara otomatis mengevaluasi ekspresi pada klien. Secara default, evaluasi klien dari ekspresi yang berpotensi mahal hanya memicu peringatan.

Perilaku yang baru

Dimulai dengan 3.0, EF Core hanya memungkinkan ekspresi dalam proyeksi tingkat atas (panggilan terakhir Select() dalam kueri) untuk dievaluasi pada klien. Saat ekspresi di bagian lain kueri tidak dapat dikonversi ke SQL atau parameter, pengecualian akan dilemparkan.

Mengapa

Evaluasi kueri klien otomatis memungkinkan banyak kueri dijalankan bahkan jika bagian penting dari kueri tersebut tidak dapat diterjemahkan. Perilaku ini dapat mengakibatkan perilaku yang tidak terduga dan berpotensi merusak yang mungkin hanya terlihat dalam produksi. Misalnya, kondisi dalam Where() panggilan yang tidak dapat diterjemahkan dapat menyebabkan semua baris dari tabel ditransfer dari server database, dan filter yang akan diterapkan pada klien. Situasi ini dapat dengan mudah tidak terdeteksi jika tabel hanya berisi beberapa baris dalam pengembangan, tetapi terpukul keras ketika aplikasi pindah ke produksi, di mana tabel mungkin berisi jutaan baris. Peringatan evaluasi klien juga terbukti terlalu mudah diabaikan selama pengembangan.

Selain itu, evaluasi klien otomatis dapat menyebabkan masalah di mana meningkatkan terjemahan kueri untuk ekspresi tertentu menyebabkan perubahan yang tidak diinginkan di antara rilis.

Mitigasi

Jika kueri tidak dapat sepenuhnya diterjemahkan, maka tulis ulang kueri dalam formulir yang dapat diterjemahkan, atau gunakan AsEnumerable(), ToList(), atau mirip dengan secara eksplisit membawa data kembali ke klien tempat kueri tersebut kemudian dapat diproses lebih lanjut menggunakan LINQ-to-Objects.

Perubahan dampak sedang

Entity Framework Core tidak lagi menjadi bagian dari kerangka kerja bersama ASP.NET Core

Melacak Pengumuman Masalah#325

Perilaku yang lama

Sebelum ASP.NET Core 3.0, ketika Anda menambahkan referensi paket ke Microsoft.AspNetCore.App atau Microsoft.AspNetCore.All, itu akan mencakup EF Core dan beberapa penyedia data EF Core seperti penyedia SQL Server.

Perilaku yang baru

Mulai 3.0, kerangka kerja bersama ASP.NET Core tidak menyertakan EF Core atau penyedia data EF Core apa pun.

Mengapa

Sebelum perubahan ini, mendapatkan EF Core memerlukan langkah-langkah yang berbeda tergantung pada apakah aplikasi yang ditargetkan ASP.NET Core dan SQL Server atau tidak. Selain itu, meningkatkan ASP.NET Core memaksa peningkatan EF Core dan penyedia SQL Server, yang tidak selalu diinginkan.

Dengan perubahan ini, pengalaman mendapatkan EF Core sama di semua penyedia, implementasi .NET yang didukung, dan jenis aplikasi. Pengembang juga sekarang dapat mengontrol dengan tepat kapan penyedia data EF Core dan EF Core ditingkatkan.

Mitigasi

Untuk menggunakan EF Core dalam aplikasi ASP.NET Core 3.0 atau aplikasi lain yang didukung, tambahkan referensi paket secara eksplisit ke penyedia database EF Core yang akan digunakan aplikasi Anda.

Alat baris perintah EF Core, dotnet ef, bukan lagi bagian dari .NET Core SDK

Masalah Pelacakan #14016

Perilaku yang lama

Sebelum 3.0, dotnet ef alat ini disertakan dalam .NET Core SDK dan siap digunakan dari baris perintah dari proyek apa pun tanpa memerlukan langkah tambahan.

Perilaku yang baru

Mulai dari 3.0, .NET SDK tidak menyertakan dotnet ef alat, jadi sebelum Anda dapat menggunakannya, Anda harus menginstalnya secara eksplisit sebagai alat lokal atau global.

Mengapa

Perubahan ini memungkinkan kami untuk mendistribusikan dan memperbarui dotnet ef sebagai alat .NET CLI biasa di NuGet, konsisten dengan fakta bahwa EF Core 3.0 juga selalu didistribusikan sebagai paket NuGet.

Mitigasi

Untuk dapat mengelola migrasi atau perancah DbContext, instal dotnet-ef sebagai alat global:

dotnet tool install --global dotnet-ef

Anda juga dapat memperolehnya alat lokal saat memulihkan dependensi proyek yang menyatakannya sebagai dependensi alat menggunakan file manifes alat.

Perubahan berdampak rendah

FromSql, ExecuteSql, dan ExecuteSqlAsync telah diganti namanya

Masalah Pelacakan #10996

Penting

ExecuteSqlCommand dan ExecuteSqlCommandAsync tidak digunakan lagi. Gunakan metode ini sebagai gantinya.

Perilaku yang lama

Sebelum EF Core 3.0, nama metode ini kelebihan beban untuk bekerja dengan string normal atau string yang harus diinterpolasi ke dalam SQL dan parameter.

Perilaku yang baru

Dimulai dengan EF Core 3.0, gunakan FromSqlRaw, ExecuteSqlRaw, dan ExecuteSqlRawAsync untuk membuat kueri berparameter di mana parameter diteruskan secara terpisah dari string kueri. Contohnya:

context.Products.FromSqlRaw(
    "SELECT * FROM Products WHERE Name = {0}",
    product.Name);

Gunakan FromSqlInterpolated, ExecuteSqlInterpolated, dan ExecuteSqlInterpolatedAsync untuk membuat kueri berparameter di mana parameter diteruskan sebagai bagian dari string kueri terinterpolasi. Contohnya:

context.Products.FromSqlInterpolated(
    $"SELECT * FROM Products WHERE Name = {product.Name}");

Perhatikan bahwa kedua kueri di atas akan menghasilkan SQL parameter yang sama dengan parameter SQL yang sama.

Mengapa

Metode kelebihan beban seperti ini membuatnya sangat mudah untuk secara tidak sengaja memanggil metode string mentah ketika niatnya adalah untuk memanggil metode string yang diinterpolasi, dan sebaliknya. Hal ini dapat mengakibatkan kueri tidak diparameterkan ketika seharusnya.

Mitigasi

Beralih untuk menggunakan nama metode baru.

Metode FromSql saat digunakan dengan prosedur tersimpan tidak dapat disusur

Masalah Pelacakan #15392

Perilaku yang lama

Sebelum EF Core 3.0, metode FromSql mencoba mendeteksi apakah SQL yang diteruskan dapat terdiri. Ini melakukan evaluasi klien ketika SQL tidak dapat dikomposisikan seperti prosedur tersimpan. Kueri berikut bekerja dengan menjalankan prosedur tersimpan di server dan melakukan FirstOrDefault di sisi klien.

context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();

Perilaku yang baru

Dimulai dengan EF Core 3.0, EF Core tidak akan mencoba mengurai SQL. Jadi jika Anda menyusun setelah FromSqlRaw/FromSqlInterpolated, maka EF Core akan menyusun SQL dengan menyebabkan sub kueri. Jadi jika Anda menggunakan prosedur tersimpan dengan komposisi maka Anda akan mendapatkan pengecualian untuk sintaks SQL yang tidak valid.

Mengapa

EF Core 3.0 tidak mendukung evaluasi klien otomatis, karena rawan kesalahan seperti yang dijelaskan di sini.

Mitigasi

Jika Anda menggunakan prosedur tersimpan di FromSqlRaw/FromSqlInterpolated, Anda tahu bahwa prosedur tersebut tidak dapat disusam, sehingga Anda dapat menambahkan AsEnumerable/AsAsyncEnumerable tepat setelah panggilan metode FromSql untuk menghindari komposisi apa pun di sisi server.

context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();

Metode FromSql hanya dapat ditentukan pada akar kueri

Masalah Pelacakan #15704

Perilaku yang lama

Sebelum EF Core 3.0, FromSql metode dapat ditentukan di mana saja dalam kueri.

Perilaku yang baru

Dimulai dengan EF Core 3.0, metode dan baru FromSqlRaw (yang menggantikan FromSql) hanya dapat ditentukan pada akar kueri, yaitu langsung pada DbSet<>.FromSqlInterpolated Mencoba menentukannya di tempat lain akan mengakibatkan kesalahan kompilasi.

Mengapa

Menentukan FromSql di mana saja selain pada DbSet yang tidak memiliki arti tambahan atau nilai tambah, dan dapat menyebabkan ambiguitas dalam skenario tertentu.

Mitigasi

FromSql pemanggilan harus dipindahkan untuk langsung di mana DbSet mereka menerapkannya.

Kueri tanpa pelacakan tidak lagi melakukan resolusi identitas

Masalah Pelacakan #13518

Perilaku yang lama

Sebelum EF Core 3.0, instans entitas yang sama akan digunakan untuk setiap kemunculan entitas dengan jenis dan ID tertentu. Ini cocok dengan perilaku kueri pelacakan. Misalnya, kueri ini:

var results = context.Products.Include(e => e.Category).AsNoTracking().ToList();

akan mengembalikan instans yang sama Category untuk masing-masing Product yang terkait dengan kategori yang diberikan.

Perilaku yang baru

Dimulai dengan EF Core 3.0, instans entitas yang berbeda akan dibuat ketika entitas dengan jenis dan ID tertentu ditemui di tempat yang berbeda dalam grafik yang dikembalikan. Misalnya, kueri di atas sekarang akan mengembalikan instans baru Category untuk masing-masing Product bahkan ketika dua produk dikaitkan dengan kategori yang sama.

Mengapa

Resolusi identitas (yaitu, menentukan bahwa entitas memiliki jenis dan ID yang sama dengan entitas yang ditemui sebelumnya) menambahkan performa tambahan dan overhead memori. Ini biasanya menjalankan penghitung mengapa kueri tanpa pelacakan digunakan di tempat pertama. Selain itu, meskipun resolusi identitas terkadang dapat berguna, tidak diperlukan jika entitas akan diserialisasikan dan dikirim ke klien, yang umum untuk kueri tanpa pelacakan.

Mitigasi

Gunakan kueri pelacakan jika resolusi identitas diperlukan.

Nilai kunci sementara tidak lagi diatur ke instans entitas

Masalah Pelacakan #12378

Perilaku yang lama

Sebelum EF Core 3.0, nilai sementara ditetapkan ke semua properti kunci yang nantinya akan memiliki nilai nyata yang dihasilkan oleh database. Biasanya nilai sementara ini adalah angka negatif yang besar.

Perilaku yang baru

Dimulai dengan 3.0, EF Core menyimpan nilai kunci sementara sebagai bagian dari informasi pelacakan entitas, dan membiarkan properti kunci itu sendiri tidak berubah.

Mengapa

Perubahan ini dilakukan untuk mencegah nilai kunci sementara menjadi permanen secara keliru ketika entitas yang sebelumnya telah dilacak oleh beberapa DbContext instans dipindahkan ke instans yang berbeda DbContext .

Mitigasi

Aplikasi yang menetapkan nilai kunci utama ke kunci asing untuk membentuk asosiasi antar entitas dapat bergantung pada perilaku lama jika kunci utama dibuat dan milik entitas dalam Added status. Hal ini dapat dihindari dengan:

  • Tidak menggunakan kunci yang dihasilkan penyimpanan.
  • Mengatur properti navigasi ke hubungan formulir alih-alih mengatur nilai kunci asing.
  • Dapatkan nilai kunci sementara aktual dari informasi pelacakan entitas. Misalnya, context.Entry(blog).Property(e => e.Id).CurrentValue akan mengembalikan nilai sementara meskipun blog.Id belum ditetapkan.

DetectChanges menghormati nilai kunci yang dihasilkan penyimpanan

Masalah Pelacakan #14616

Perilaku yang lama

Sebelum EF Core 3.0, entitas yang tidak terlacak yang ditemukan oleh DetectChanges akan dilacak dalam Added status dan dimasukkan sebagai baris baru saat SaveChanges dipanggil.

Perilaku yang baru

Dimulai dengan EF Core 3.0, jika entitas menggunakan nilai kunci yang dihasilkan dan beberapa nilai kunci diatur, maka entitas akan dilacak dalam Modified status . Ini berarti bahwa baris untuk entitas diasumsikan ada dan akan diperbarui ketika SaveChanges dipanggil. Jika nilai kunci tidak diatur, atau jika jenis entitas tidak menggunakan kunci yang dihasilkan, maka entitas baru masih akan dilacak seperti Added pada versi sebelumnya.

Mengapa

Perubahan ini dilakukan untuk mempermudah dan lebih konsisten untuk bekerja dengan grafik entitas yang terputus saat menggunakan kunci yang dihasilkan penyimpanan.

Mitigasi

Perubahan ini dapat merusak aplikasi jika jenis entitas dikonfigurasi untuk menggunakan kunci yang dihasilkan tetapi nilai kunci secara eksplisit diatur untuk instans baru. Perbaikannya adalah mengonfigurasi properti kunci secara eksplisit untuk tidak menggunakan nilai yang dihasilkan. Misalnya, dengan API yang fasih:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedNever();

Atau dengan anotasi data:

[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }

Penghapusan kaskade sekarang terjadi segera secara default

Masalah Pelacakan #10114

Perilaku yang lama

Sebelum 3.0, tindakan berjenjang yang diterapkan EF Core (menghapus entitas dependen ketika prinsipal yang diperlukan dihapus atau ketika hubungan dengan prinsipal yang diperlukan terputus) tidak terjadi sampai SaveChanges dipanggil.

Perilaku yang baru

Dimulai dengan 3.0, EF Core menerapkan tindakan kaskade segera setelah kondisi pemicu terdeteksi. Misalnya, panggilan context.Remove() untuk menghapus entitas utama akan mengakibatkan semua dependen terkait yang diperlukan yang dilacak juga diatur ke Deleted segera.

Mengapa

Perubahan ini dilakukan untuk meningkatkan pengalaman untuk skenario pengikatan dan audit data di mana penting untuk memahami entitas mana yang akan dihapus sebelum SaveChanges dipanggil.

Mitigasi

Perilaku sebelumnya dapat dipulihkan melalui pengaturan pada context.ChangeTracker. Contohnya:

context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;

Masalah pelacakan #18022

Perilaku yang lama

Sebelum 3.0, dengan bersemangat memuat navigasi pengumpulan melalui Include operator menyebabkan beberapa kueri dihasilkan pada database relasional, satu untuk setiap jenis entitas terkait.

Perilaku yang baru

Dimulai dengan 3.0, EF Core menghasilkan satu kueri dengan JOIN pada database relasional.

Mengapa

Mengeluarkan beberapa kueri untuk mengimplementasikan satu kueri LINQ menyebabkan banyak masalah, termasuk performa negatif karena beberapa perjalanan pulang-pergi database diperlukan, dan masalah koherensi data karena setiap kueri dapat mengamati status database yang berbeda.

Mitigasi

Meskipun secara teknis ini bukan perubahan yang melanggar, ini bisa memiliki efek yang cukup besar pada performa aplikasi ketika satu kueri berisi sejumlah Include besar operator pada navigasi koleksi. Lihat komentar ini untuk informasi selengkapnya dan untuk menulis ulang kueri dengan cara yang lebih efisien.

**

DeleteBehavior.Restrict memiliki semantik yang lebih bersih

Masalah Pelacakan #12661

Perilaku yang lama

Sebelum 3.0, DeleteBehavior.Restrict kunci asing yang dibuat dalam database dengan semantik, tetapi juga mengubah perbaikan internal dengan Restrict cara yang tidak jelas.

Perilaku yang baru

Dimulai dengan 3.0, DeleteBehavior.Restrict memastikan bahwa kunci asing dibuat dengan Restrict semantik --yaitu, tidak ada kaskade; melemparkan pelanggaran batasan --tanpa juga berdampak pada perbaikan internal EF.

Mengapa

Perubahan ini dilakukan untuk meningkatkan pengalaman penggunaan DeleteBehavior dengan cara yang intuitif, tanpa efek samping yang tidak terduga.

Mitigasi

Perilaku sebelumnya dapat dipulihkan dengan menggunakan DeleteBehavior.ClientNoAction.

Jenis kueri dikonsolidasikan dengan jenis entitas

Masalah Pelacakan #14194

Perilaku yang lama

Sebelum EF Core 3.0, jenis kueri adalah sarana untuk mengkueri data yang tidak menentukan kunci utama dengan cara terstruktur. Artinya, jenis kueri digunakan untuk memetakan jenis entitas tanpa kunci (kemungkinan besar dari tampilan, tetapi mungkin dari tabel) sementara jenis entitas reguler digunakan ketika kunci tersedia (kemungkinan besar dari tabel, tetapi mungkin dari tampilan).

Perilaku yang baru

Jenis kueri sekarang hanya menjadi jenis entitas tanpa kunci utama. Jenis entitas tanpa kunci memiliki fungsionalitas yang sama dengan jenis kueri di versi sebelumnya.

Mengapa

Perubahan ini dilakukan untuk mengurangi kebingungan sekeliling tujuan jenis kueri. Secara khusus, mereka adalah jenis entitas tanpa kunci dan secara inheren baca-saja karena ini, tetapi tidak boleh digunakan hanya karena jenis entitas perlu dibaca-saja. Demikian juga, mereka sering dipetakan ke tampilan, tetapi ini hanya karena tampilan sering tidak menentukan kunci.

Mitigasi

Bagian API berikut sekarang usang:

  • ModelBuilder.Query<>() - Sebaliknya ModelBuilder.Entity<>().HasNoKey() perlu dipanggil untuk menandai jenis entitas karena tidak memiliki kunci. Ini masih tidak akan dikonfigurasi oleh konvensi untuk menghindari kesalahan konfigurasi ketika kunci primer diharapkan, tetapi tidak cocok dengan konvensi.
  • DbQuery<> - Sebagai gantinya DbSet<> harus digunakan.
  • DbContext.Query<>() - Sebagai gantinya DbContext.Set<>() harus digunakan.
  • IQueryTypeConfiguration<TQuery> - Sebagai gantinya IEntityTypeConfiguration<TEntity> harus digunakan.

Catatan

Karena masalah dalam 3.x saat mengkueri entitas tanpa kunci yang memiliki semua properti yang diatur ke null null akan dikembalikan alih-alih entitas, jika masalah ini berlaku untuk skenario Anda juga menambahkan logika untuk menangani null hasil.

API Konfigurasi untuk hubungan jenis yang dimiliki telah berubah

Masalah Pelacakan #12444Masalah Pelacakan #9148Masalah Pelacakan #14153

Perilaku yang lama

Sebelum EF Core 3.0, konfigurasi hubungan yang dimiliki dilakukan langsung setelah OwnsOne panggilan atau OwnsMany .

Perilaku yang baru

Dimulai dengan EF Core 3.0, sekarang ada API yang fasih untuk mengonfigurasi properti navigasi kepada pemilik menggunakan WithOwner(). Contohnya:

modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);

Konfigurasi yang terkait dengan hubungan antara pemilik dan yang dimiliki sekarang harus ditautkan setelah WithOwner() mirip dengan bagaimana hubungan lain dikonfigurasi. Sementara konfigurasi untuk jenis yang dimiliki itu sendiri masih akan ditautkan setelah OwnsOne()/OwnsMany(). Contohnya:

modelBuilder.Entity<Order>.OwnsOne(e => e.Details, eb =>
    {
        eb.WithOwner()
            .HasForeignKey(e => e.AlternateId)
            .HasConstraintName("FK_OrderDetails");

        eb.ToTable("OrderDetails");
        eb.HasKey(e => e.AlternateId);
        eb.HasIndex(e => e.Id);

        eb.HasOne(e => e.Customer).WithOne();

        eb.HasData(
            new OrderDetails
            {
                AlternateId = 1,
                Id = -1
            });
    });

Selain itu memanggil Entity(), HasOne(), atau Set() dengan target jenis yang dimiliki sekarang akan melemparkan pengecualian.

Mengapa

Perubahan ini dilakukan untuk membuat pemisahan yang lebih bersih antara mengonfigurasi jenis yang dimiliki itu sendiri dan hubungan dengan jenis yang dimiliki. Ini pada gilirannya menghilangkan ambiguitas dan kebingungan di sekitar metode seperti HasForeignKey.

Mitigasi

Ubah konfigurasi hubungan jenis yang dimiliki untuk menggunakan permukaan API baru seperti yang ditunjukkan pada contoh di atas.

Entitas dependen yang berbagi tabel dengan prinsipal sekarang bersifat opsional

Masalah Pelacakan #9005

Perilaku yang lama

Perhatikan model berikut:

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

public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

Sebelum EF Core 3.0, jika OrderDetails dimiliki oleh Order atau secara eksplisit dipetakan ke tabel yang sama maka OrderDetails instans selalu diperlukan saat menambahkan baru Order.

Perilaku yang baru

Dimulai dengan 3.0, EF Core memungkinkan untuk menambahkan Order tanpa OrderDetails dan memetakan semua OrderDetails properti kecuali kunci utama ke kolom nullable. Saat mengkueri EF Core diatur OrderDetails ke null jika salah satu properti yang diperlukan tidak memiliki nilai atau jika tidak memiliki properti yang diperlukan selain kunci utama dan semua properti adalah null.

Mitigasi

Jika model Anda memiliki berbagi tabel tergantung pada semua kolom opsional, tetapi navigasi yang menunjuk ke null model tersebut tidak diharapkan maka aplikasi harus dimodifikasi untuk menangani kasus ketika navigasi adalah null. Jika ini tidak memungkinkan properti yang diperlukan harus ditambahkan ke jenis entitas atau setidaknya satu properti harus memiliki non-nilainull yang ditetapkan untuk properti tersebut.

Semua entitas yang berbagi tabel dengan kolom token konkurensi harus memetakannya ke properti

Masalah Pelacakan #14154

Perilaku yang lama

Perhatikan model berikut:

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public byte[] Version { get; set; }
    public OrderDetails Details { get; set; }
}

public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Order>()
        .Property(o => o.Version).IsRowVersion().HasColumnName("Version");
}

Sebelum EF Core 3.0, jika OrderDetails dimiliki oleh Order atau secara eksplisit dipetakan ke tabel yang sama, maka memperbarui hanya OrderDetails tidak akan memperbarui Version nilai pada klien dan pembaruan berikutnya akan gagal.

Perilaku yang baru

Dimulai dengan 3.0, EF Core menyebarluaskan nilai baru Version jika Order memiliki OrderDetails. Jika tidak, pengecualian dilemparkan selama validasi model.

Mengapa

Perubahan ini dilakukan untuk menghindari nilai token konkurensi kedaluarsa ketika hanya salah satu entitas yang dipetakan ke tabel yang sama yang diperbarui.

Mitigasi

Semua entitas yang berbagi tabel harus menyertakan properti yang dipetakan ke kolom token konkurensi. Ada kemungkinan membuatnya dalam keadaan bayangan:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<OrderDetails>()
        .Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}

Entitas yang dimiliki tidak dapat dikueri tanpa pemilik menggunakan kueri pelacakan

Masalah Pelacakan #18876

Perilaku yang lama

Sebelum EF Core 3.0, entitas yang dimiliki dapat dikueri sebagai navigasi lainnya.

context.People.Select(p => p.Address);

Perilaku yang baru

Dimulai dengan 3.0, EF Core akan melempar jika kueri pelacakan memproyeksikan entitas yang dimiliki tanpa pemilik.

Mengapa

Entitas yang dimiliki tidak dapat dimanipulasi tanpa pemilik, jadi dalam sebagian besar kasus yang mengkuerinya dengan cara ini adalah kesalahan.

Mitigasi

Jika entitas yang dimiliki harus dilacak untuk dimodifikasi dengan cara apa pun nanti, pemilik harus disertakan dalam kueri.

Jika tidak, tambahkan AsNoTracking() panggilan:

context.People.Select(p => p.Address).AsNoTracking();

Properti yang diwariskan dari jenis yang tidak dipetakan sekarang dipetakan ke satu kolom untuk semua jenis turunan

Masalah Pelacakan #13998

Perilaku yang lama

Perhatikan model berikut:

public abstract class EntityBase
{
    public int Id { get; set; }
}

public abstract class OrderBase : EntityBase
{
    public int ShippingAddress { get; set; }
}

public class BulkOrder : OrderBase
{
}

public class Order : OrderBase
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OrderBase>();
    modelBuilder.Entity<EntityBase>();
    modelBuilder.Entity<BulkOrder>();
    modelBuilder.Entity<Order>();
}

Sebelum EF Core 3.0, ShippingAddress properti akan dipetakan ke kolom terpisah untuk BulkOrder dan Order secara default.

Perilaku yang baru

Dimulai dengan 3.0, EF Core hanya membuat satu kolom untuk ShippingAddress.

Mengapa

Perilaku lama itu tak terduga.

Mitigasi

Properti masih dapat dipetakan secara eksplisit untuk memisahkan kolom pada jenis turunan:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OrderBase>();
    modelBuilder.Entity<EntityBase>();
    modelBuilder.Entity<BulkOrder>()
        .Property(o => o.ShippingAddress).HasColumnName("BulkShippingAddress");
    modelBuilder.Entity<Order>()
        .Property(o => o.ShippingAddress).HasColumnName("ShippingAddress");
}

Konvensi properti kunci asing tidak lagi cocok dengan nama yang sama dengan properti utama

Masalah Pelacakan #13274

Perilaku yang lama

Perhatikan model berikut:

public class Customer
{
    public int CustomerId { get; set; }
    public ICollection<Order> Orders { get; set; }
}

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

Sebelum EF Core 3.0, CustomerId properti akan digunakan untuk kunci asing berdasarkan konvensi. Namun, jika Order adalah jenis yang dimiliki, maka ini juga akan membuat CustomerId kunci primer dan ini biasanya bukan harapan.

Perilaku yang baru

Dimulai dengan 3.0, EF Core tidak mencoba menggunakan properti untuk kunci asing berdasarkan konvensi jika mereka memiliki nama yang sama dengan properti utama. Nama jenis utama yang digabungkan dengan nama properti utama, dan nama navigasi yang digabungkan dengan pola nama properti utama masih cocok. Contohnya:

public class Customer
{
    public int Id { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
}
public class Customer
{
    public int Id { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int BuyerId { get; set; }
    public Customer Buyer { get; set; }
}

Mengapa

Perubahan ini dilakukan untuk menghindari keliru menentukan properti kunci primer pada jenis yang dimiliki.

Mitigasi

Jika properti dimaksudkan untuk menjadi kunci asing, dan karenanya bagian dari kunci primer, maka konfigurasikan secara eksplisit seperti itu.

Koneksi database sekarang ditutup jika tidak digunakan lagi sebelum TransactionScope selesai

Masalah Pelacakan #14218

Perilaku yang lama

Sebelum EF Core 3.0, jika konteks membuka koneksi di dalam TransactionScope, koneksi tetap terbuka saat saat ini TransactionScope aktif.

using (new TransactionScope())
{
    using (AdventureWorks context = new AdventureWorks())
    {
        context.ProductCategories.Add(new ProductCategory());
        context.SaveChanges();

        // Old behavior: Connection is still open at this point

        var categories = context.ProductCategories().ToList();
    }
}

Perilaku yang baru

Dimulai dengan 3.0, EF Core menutup koneksi segera setelah selesai menggunakannya.

Mengapa

Perubahan ini memungkinkan untuk menggunakan beberapa konteks dalam hal yang sama TransactionScope. Perilaku baru juga cocok dengan EF6.

Mitigasi

Jika koneksi perlu tetap terbuka, panggilan eksplisit ke OpenConnection() akan memastikan bahwa EF Core tidak menutupnya sebelum waktunya:

using (new TransactionScope())
{
    using (AdventureWorks context = new AdventureWorks())
    {
        context.Database.OpenConnection();
        context.ProductCategories.Add(new ProductCategory());
        context.SaveChanges();

        var categories = context.ProductCategories().ToList();
        context.Database.CloseConnection();
    }
}

Setiap properti menggunakan pembuatan kunci bilangan bulat dalam memori independen

Masalah Pelacakan #6872

Perilaku yang lama

Sebelum EF Core 3.0, satu generator nilai bersama digunakan untuk semua properti kunci bilangan bulat dalam memori.

Perilaku yang baru

Dimulai dengan EF Core 3.0, setiap properti kunci bilangan bulat mendapatkan generator nilainya sendiri saat menggunakan database dalam memori. Selain itu, jika database dihapus, pembuatan kunci diatur ulang untuk semua tabel.

Mengapa

Perubahan ini dilakukan untuk menyelaraskan pembuatan kunci dalam memori lebih dekat dengan pembuatan kunci database nyata dan untuk meningkatkan kemampuan untuk mengisolasi pengujian satu sama lain saat menggunakan database dalam memori.

Mitigasi

Ini dapat merusak aplikasi yang mengandalkan nilai kunci dalam memori tertentu untuk diatur. Pertimbangkan untuk tidak mengandalkan nilai kunci tertentu, atau memperbarui agar sesuai dengan perilaku baru.

Bidang penolakan digunakan secara default

Masalah Pelacakan #12430

Perilaku yang lama

Sebelum 3.0, bahkan jika bidang pencadangan untuk properti diketahui, EF Core masih akan secara default membaca dan menulis nilai properti menggunakan metode getter dan setter properti. Pengecualian untuk ini adalah eksekusi kueri, di mana bidang penolakan akan diatur secara langsung jika diketahui.

Perilaku yang baru

Dimulai dengan EF Core 3.0, jika bidang pencadangan untuk properti diketahui, maka EF Core akan selalu membaca dan menulis properti tersebut menggunakan bidang backing. Ini dapat menyebabkan pemutusan aplikasi jika aplikasi mengandalkan perilaku tambahan yang dikodekan ke dalam metode getter atau setter.

Mengapa

Perubahan ini dilakukan untuk mencegah EF Core secara keliru memicu logika bisnis secara default saat melakukan operasi database yang melibatkan entitas.

Mitigasi

Perilaku pra-3.0 dapat dipulihkan melalui konfigurasi mode akses properti pada ModelBuilder. Contohnya:

modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);

Lempar jika beberapa bidang backing yang kompatibel ditemukan

Masalah Pelacakan #12523

Perilaku yang lama

Sebelum EF Core 3.0, jika beberapa bidang cocok dengan aturan untuk menemukan bidang dukungan properti, maka satu bidang akan dipilih berdasarkan beberapa urutan prioritas. Ini dapat menyebabkan bidang yang salah digunakan dalam kasus ambigu.

Perilaku yang baru

Dimulai dengan EF Core 3.0, jika beberapa bidang dicocokkan dengan properti yang sama, maka pengecualian akan dilemparkan.

Mengapa

Perubahan ini dilakukan untuk menghindari diam-diam menggunakan satu bidang di atas bidang lain ketika hanya satu yang dapat benar.

Mitigasi

Properti dengan bidang dukungan ambigu harus memiliki bidang untuk digunakan secara eksplisit. Misalnya, menggunakan API yang fasih:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .HasField("_id");

Nama properti bidang saja harus cocok dengan nama bidang

Perilaku yang lama

Sebelum EF Core 3.0, properti dapat ditentukan oleh nilai string dan jika tidak ada properti dengan nama tersebut yang ditemukan pada jenis .NET, maka EF Core akan mencoba mencocokkannya dengan bidang menggunakan aturan konvensi.

private class Blog
{
    private int _id;
    public string Name { get; set; }
}
modelBuilder
    .Entity<Blog>()
    .Property("Id");

Perilaku yang baru

Dimulai dengan EF Core 3.0, properti khusus bidang harus sama persis dengan nama bidang.

modelBuilder
    .Entity<Blog>()
    .Property("_id");

Mengapa

Perubahan ini dilakukan untuk menghindari penggunaan bidang yang sama untuk dua properti bernama serupa, ini juga membuat aturan pencocokan untuk properti khusus bidang sama seperti untuk properti yang dipetakan ke properti CLR.

Mitigasi

Properti khusus bidang harus dinamai sama dengan bidang yang dipetakan. Dalam rilis EF Core di masa mendatang setelah 3.0, kami berencana untuk mengaktifkan kembali konfigurasi nama bidang yang berbeda dari nama properti secara eksplisit (lihat masalah #15307):

modelBuilder
    .Entity<Blog>()
    .Property("Id")
    .HasField("_id");

AddDbContext/AddDbContextPool tidak lagi memanggil AddLogging dan AddMemoryCache

Masalah Pelacakan #14756

Perilaku yang lama

Sebelum EF Core 3.0, memanggil AddDbContext atau AddDbContextPool juga akan mendaftarkan layanan pengelogan dan penembolokan memori dengan DI melalui panggilan ke AddLogging dan AddMemoryCache.

Perilaku yang baru

Dimulai dengan EF Core 3.0, AddDbContext dan AddDbContextPool tidak akan lagi mendaftarkan layanan ini dengan Dependency Injection (DI).

Mengapa

EF Core 3.0 tidak mengharuskan layanan ini berada dalam kontainer DI aplikasi. Namun, jika ILoggerFactory terdaftar dalam kontainer DI aplikasi, maka itu masih akan digunakan oleh EF Core.

Mitigasi

Jika aplikasi Anda membutuhkan layanan ini, daftarkan secara eksplisit dengan kontainer DI menggunakan AddLogging atau AddMemoryCache.

AddEntityFramework* menambahkan IMemoryCache dengan batas ukuran

Masalah Pelacakan #12905

Perilaku yang lama

Sebelum EF Core 3.0, metode panggilan AddEntityFramework* juga akan mendaftarkan layanan penembolokan memori dengan DI tanpa batas ukuran.

Perilaku yang baru

Dimulai dengan EF Core 3.0, AddEntityFramework* akan mendaftarkan layanan IMemoryCache dengan batas ukuran. Jika ada layanan lain yang ditambahkan setelahnya bergantung pada IMemoryCache, layanan tersebut dapat dengan cepat mencapai batas default yang menyebabkan pengecualian atau performa yang terdegradasi.

Mengapa

Menggunakan IMemoryCache tanpa batas dapat mengakibatkan penggunaan memori yang tidak terkendali jika ada bug dalam logika penembolokan kueri atau kueri dihasilkan secara dinamis. Memiliki batas default mengurangi potensi serangan DoS.

Mitigasi

Dalam kebanyakan kasus, panggilan AddEntityFramework* tidak diperlukan jika AddDbContext atau AddDbContextPool dipanggil juga. Oleh karena itu, mitigasi terbaik adalah menghapus AddEntityFramework* panggilan.

Jika aplikasi Anda membutuhkan layanan ini, maka daftarkan implementasi IMemoryCache secara eksplisit dengan kontainer DI sebelumnya menggunakan AddMemoryCache.

DbContext.Entry sekarang melakukan DetectChanges lokal

Masalah Pelacakan #13552

Perilaku yang lama

Sebelum EF Core 3.0, panggilan DbContext.Entry akan menyebabkan perubahan terdeteksi untuk semua entitas yang dilacak. Ini memastikan bahwa status yang terekspos dalam EntityEntry sudah diperbarui.

Perilaku yang baru

Dimulai dengan EF Core 3.0, panggilan DbContext.Entry sekarang hanya akan mencoba mendeteksi perubahan pada entitas tertentu dan entitas utama yang dilacak yang terkait dengannya. Ini berarti bahwa perubahan di tempat lain mungkin tidak terdeteksi dengan memanggil metode ini, yang dapat memiliki implikasi pada status aplikasi.

Perhatikan bahwa jika ChangeTracker.AutoDetectChangesEnabled diatur ke false maka bahkan deteksi perubahan lokal ini akan dinonaktifkan.

Metode lain yang menyebabkan deteksi perubahan--misalnya ChangeTracker.Entries dan SaveChanges--masih menyebabkan penuhnya DetectChanges semua entitas yang dilacak.

Mengapa

Perubahan ini dilakukan untuk meningkatkan performa default penggunaan context.Entry.

Mitigasi

Panggil ChangeTracker.DetectChanges() secara eksplisit sebelum memanggil Entry untuk memastikan perilaku pra-3.0.

Kunci array string dan byte tidak dihasilkan klien secara default

Masalah Pelacakan #14617

Perilaku yang lama

Sebelum EF Core 3.0, string dan byte[] properti kunci dapat digunakan tanpa secara eksplisit mengatur nilai non-null. Dalam kasus seperti itu, nilai kunci akan dihasilkan pada klien sebagai GUID, diserialisasikan ke byte untuk byte[].

Perilaku yang baru

Dimulai dengan EF Core 3.0 pengecualian akan dilemparkan yang menunjukkan bahwa tidak ada nilai kunci yang telah ditetapkan.

Mengapa

Perubahan ini dilakukan karena nilai yang dihasilkan string/byte[] klien umumnya tidak berguna, dan perilaku default membuatnya sulit untuk beralasan tentang nilai kunci yang dihasilkan dengan cara yang sama.

Mitigasi

Perilaku pra-3.0 dapat diperoleh dengan secara eksplisit menentukan bahwa properti kunci harus menggunakan nilai yang dihasilkan jika tidak ada nilai non-null lainnya yang ditetapkan. Misalnya, dengan API yang fasih:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedOnAdd();

Atau dengan anotasi data:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }

ILoggerFactory sekarang menjadi layanan terlingkup

Masalah Pelacakan #14698

Perilaku yang lama

Sebelum EF Core 3.0, ILoggerFactory terdaftar sebagai layanan singleton.

Perilaku yang baru

Dimulai dengan EF Core 3.0, ILoggerFactory sekarang terdaftar sebagai cakupan.

Mengapa

Perubahan ini dilakukan untuk memungkinkan asosiasi pencatat dengan DbContext instans, yang memungkinkan fungsionalitas lain dan menghapus beberapa kasus perilaku patologis seperti ledakan penyedia layanan internal.

Mitigasi

Perubahan ini tidak boleh memengaruhi kode aplikasi kecuali mendaftar dan menggunakan layanan kustom pada penyedia layanan internal EF Core. Hal ini tidak umum. Dalam kasus ini, sebagian besar hal masih akan berfungsi, tetapi layanan singleton apa pun yang bergantung pada ILoggerFactory perlu diubah untuk mendapatkan dengan ILoggerFactory cara yang berbeda.

Jika Anda mengalami situasi seperti ini, silakan ajukan masalah pada pelacak masalah EF Core GitHub untuk memberi tahu kami bagaimana Anda menggunakannya ILoggerFactory sehingga kami dapat lebih memahami cara untuk tidak memecahkan ini lagi di masa depan.

Proksi pemuatan malas tidak lagi mengasumsikan properti navigasi dimuat sepenuhnya

Masalah Pelacakan #12780

Perilaku yang lama

Sebelum EF Core 3.0, setelah DbContext dibuang, tidak ada cara untuk mengetahui apakah properti navigasi tertentu pada entitas yang diperoleh dari konteks tersebut dimuat sepenuhnya atau tidak. Proksi akan mengasumsikan bahwa navigasi referensi dimuat jika memiliki nilai non-null, dan navigasi koleksi dimuat jika tidak kosong. Dalam kasus ini, mencoba untuk malas-beban akan menjadi no-op.

Perilaku yang baru

Dimulai dengan EF Core 3.0, proksi melacak apakah properti navigasi dimuat atau tidak. Ini berarti mencoba mengakses properti navigasi yang dimuat setelah konteks dibuang akan selalu menjadi no-op, bahkan ketika navigasi yang dimuat kosong atau null. Sebaliknya, mencoba mengakses properti navigasi yang tidak dimuat akan memberikan pengecualian jika konteks dibuang meskipun properti navigasi adalah koleksi yang tidak kosong. Jika situasi ini muncul, itu berarti kode aplikasi mencoba menggunakan pemuatan malas pada waktu yang tidak valid, dan aplikasi harus diubah untuk tidak melakukan ini.

Mengapa

Perubahan ini dilakukan untuk membuat perilaku konsisten dan benar ketika mencoba untuk malas-beban pada instans yang dibuang DbContext .

Mitigasi

Perbarui kode aplikasi untuk tidak mencoba pemuatan malas dengan konteks yang dibuang, atau konfigurasikan ini menjadi no-op seperti yang dijelaskan dalam pesan pengecualian.

Pembuatan penyedia layanan internal yang berlebihan sekarang menjadi kesalahan secara default

Masalah Pelacakan #10236

Perilaku yang lama

Sebelum EF Core 3.0, peringatan akan dicatat untuk aplikasi yang membuat jumlah patologis penyedia layanan internal.

Perilaku yang baru

Dimulai dengan EF Core 3.0, peringatan ini sekarang dipertimbangkan dan kesalahan dan pengecualian dilemparkan.

Mengapa

Perubahan ini dilakukan untuk mendorong kode aplikasi yang lebih baik melalui mengekspos kasus patologis ini secara lebih eksplisit.

Mitigasi

Penyebab tindakan yang paling tepat dalam mengalami kesalahan ini adalah memahami akar penyebab dan berhenti membuat begitu banyak penyedia layanan internal. Namun, kesalahan dapat dikonversi kembali ke peringatan (atau diabaikan) melalui konfigurasi pada DbContextOptionsBuilder. Contohnya:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}

Perilaku baru untuk HasOne/HasMany dipanggil dengan satu string

Masalah Pelacakan #9171

Perilaku yang lama

Sebelum EF Core 3.0, panggilan HasOne kode atau HasMany dengan string tunggal ditafsirkan dengan cara yang membingungkan. Contohnya:

modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();

Kode terlihat seperti berkaitan dengan Samurai beberapa jenis entitas lain menggunakan Entrance properti navigasi, yang mungkin bersifat privat.

Pada kenyataannya, kode ini mencoba membuat hubungan ke beberapa jenis entitas yang disebut Entrance tanpa properti navigasi.

Perilaku yang baru

Dimulai dengan EF Core 3.0, kode di atas sekarang melakukan apa yang seharusnya dilakukan sebelumnya.

Mengapa

Perilaku lama sangat membingungkan, terutama ketika membaca kode konfigurasi dan mencari kesalahan.

Mitigasi

Ini hanya akan memutus aplikasi yang secara eksplisit mengonfigurasi hubungan menggunakan string untuk nama jenis dan tanpa menentukan properti navigasi secara eksplisit. Ini tidak umum. Perilaku sebelumnya dapat diperoleh melalui passing null eksplisit untuk nama properti navigasi. Contohnya:

modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();

Jenis pengembalian untuk beberapa metode asinkron telah diubah dari Tugas ke ValueTask

Masalah Pelacakan #15184

Perilaku yang lama

Metode asinkron berikut sebelumnya mengembalikan Task<T>:

  • DbContext.FindAsync()
  • DbSet.FindAsync()
  • DbContext.AddAsync()
  • DbSet.AddAsync()
  • ValueGenerator.NextValueAsync() (dan kelas turunan)

Perilaku yang baru

Metode yang disebutkan di atas sekarang mengembalikan lebih ValueTask<T> dari yang sama T seperti sebelumnya.

Mengapa

Perubahan ini mengurangi jumlah alokasi timbunan yang dikeluarkan saat memanggil metode ini, meningkatkan performa umum.

Mitigasi

Aplikasi hanya menunggu API di atas hanya perlu dikompilasi ulang - tidak ada perubahan sumber yang diperlukan. Penggunaan yang lebih kompleks (misalnya meneruskan yang dikembalikan Task ke Task.WhenAny()) biasanya mengharuskan ValueTask<T> pengembalian dikonversi ke dengan Task<T> memanggilnya AsTask() . Perhatikan bahwa ini meniadakan pengurangan alokasi yang dibawa oleh perubahan ini.

Anotasi Relational:TypeMapping sekarang hanya TypeMapping

Masalah Pelacakan #9913

Perilaku yang lama

Nama anotasi untuk anotasi pemetaan jenis adalah "Relational:TypeMapping".

Perilaku yang baru

Nama anotasi untuk anotasi pemetaan jenis sekarang adalah "TypeMapping".

Mengapa

Pemetaan jenis sekarang digunakan untuk lebih dari sekadar penyedia database relasional.

Mitigasi

Ini hanya akan memutus aplikasi yang mengakses pemetaan jenis secara langsung sebagai anotasi, yang tidak umum. Tindakan yang paling tepat untuk diperbaiki adalah menggunakan permukaan API untuk mengakses pemetaan jenis daripada menggunakan anotasi secara langsung.

ToTable pada jenis turunan melempar pengecualian

Masalah Pelacakan #11811

Perilaku yang lama

Sebelum EF Core 3.0, ToTable() yang dipanggil pada jenis turunan akan diabaikan karena hanya strategi pemetaan warisan adalah TPH di mana ini tidak valid.

Perilaku yang baru

Dimulai dengan EF Core 3.0 dan sebagai persiapan untuk menambahkan dukungan TPT dan TPC dalam rilis selanjutnya, ToTable() yang dipanggil pada jenis turunan sekarang akan melemparkan pengecualian untuk menghindari perubahan pemetaan yang tidak terduga di masa depan.

Mengapa

Saat ini tidak valid untuk memetakan jenis turunan ke tabel yang berbeda. Perubahan ini menghindari pemecahan di masa depan ketika menjadi hal yang valid untuk dilakukan.

Mitigasi

Hapus upaya apa pun untuk memetakan jenis turunan ke tabel lain.

ForSqlServerHasIndex diganti dengan HasIndex

Masalah Pelacakan #12366

Perilaku yang lama

Sebelum EF Core 3.0, ForSqlServerHasIndex().ForSqlServerInclude() menyediakan cara untuk mengonfigurasi kolom yang digunakan dengan INCLUDE.

Perilaku yang baru

Dimulai dengan EF Core 3.0, menggunakan Include pada indeks sekarang didukung pada tingkat relasional. Gunakan HasIndex().ForSqlServerInclude().

Mengapa

Perubahan ini dilakukan untuk mengonsolidasikan API untuk indeks dengan Include ke dalam satu tempat untuk semua penyedia database.

Mitigasi

Gunakan API baru, seperti yang ditunjukkan di atas.

Perubahan API metadata

Masalah Pelacakan #214

Perilaku yang baru

Properti berikut dikonversi ke metode ekstensi:

  • IEntityType.QueryFilter ->GetQueryFilter()
  • IEntityType.DefiningQuery ->GetDefiningQuery()
  • IProperty.IsShadowProperty ->IsShadowProperty()
  • IProperty.BeforeSaveBehavior ->GetBeforeSaveBehavior()
  • IProperty.AfterSaveBehavior ->GetAfterSaveBehavior()

Mengapa

Perubahan ini menyederhanakan implementasi antarmuka yang disebutkan di atas.

Mitigasi

Gunakan metode ekstensi baru.

Perubahan API Metadata khusus penyedia

Masalah Pelacakan #214

Perilaku yang baru

Metode ekstensi khusus penyedia akan diratakan:

  • IProperty.Relational().ColumnName ->IProperty.GetColumnName()
  • IEntityType.SqlServer().IsMemoryOptimized ->IEntityType.IsMemoryOptimized()
  • PropertyBuilder.UseSqlServerIdentityColumn() ->PropertyBuilder.UseIdentityColumn()

Mengapa

Perubahan ini menyederhanakan implementasi metode ekstensi yang disebutkan di atas.

Mitigasi

Gunakan metode ekstensi baru.

EF Core tidak lagi mengirim pragma untuk penegakan SQLite FK

Masalah Pelacakan #12151

Perilaku yang lama

Sebelum EF Core 3.0, EF Core akan mengirim PRAGMA foreign_keys = 1 ketika koneksi ke SQLite dibuka.

Perilaku yang baru

Dimulai dengan EF Core 3.0, EF Core tidak lagi mengirim PRAGMA foreign_keys = 1 ketika koneksi ke SQLite dibuka.

Mengapa

Perubahan ini dilakukan karena EF Core menggunakan SQLitePCLRaw.bundle_e_sqlite3 secara default, yang pada gilirannya berarti bahwa penegakan FK diaktifkan secara default dan tidak perlu diaktifkan secara eksplisit setiap kali koneksi dibuka.

Mitigasi

Kunci asing diaktifkan secara default di SQLitePCLRaw.bundle_e_sqlite3, yang digunakan secara default untuk EF Core. Untuk kasus lain, kunci asing dapat diaktifkan dengan menentukan Foreign Keys=True di string koneksi Anda.

Microsoft.EntityFrameworkCore.Sqlite sekarang bergantung pada SQLitePCLRaw.bundle_e_sqlite3

Perilaku yang lama

Sebelum EF Core 3.0, EF Core menggunakan SQLitePCLRaw.bundle_green.

Perilaku yang baru

Dimulai dengan EF Core 3.0, EF Core menggunakan SQLitePCLRaw.bundle_e_sqlite3.

Mengapa

Perubahan ini dilakukan agar versi SQLite yang digunakan pada iOS konsisten dengan platform lain.

Mitigasi

Untuk menggunakan versi SQLite asli di iOS, konfigurasikan Microsoft.Data.Sqlite untuk menggunakan bundel yang berbeda SQLitePCLRaw .

Nilai guid sekarang disimpan sebagai TEXT di SQLite

Masalah Pelacakan #15078

Perilaku yang lama

Nilai guid sebelumnya disimpan sebagai nilai BLOB pada SQLite.

Perilaku yang baru

Nilai guid sekarang disimpan sebagai TEXT.

Mengapa

Format biner Guids tidak distandarkan. Menyimpan nilai sebagai TEXT membuat database lebih kompatibel dengan teknologi lain.

Mitigasi

Anda dapat memigrasikan database yang sudah ada ke format baru dengan menjalankan SQL seperti berikut ini.

UPDATE MyTable
SET GuidColumn = hex(substr(GuidColumn, 4, 1)) ||
                 hex(substr(GuidColumn, 3, 1)) ||
                 hex(substr(GuidColumn, 2, 1)) ||
                 hex(substr(GuidColumn, 1, 1)) || '-' ||
                 hex(substr(GuidColumn, 6, 1)) ||
                 hex(substr(GuidColumn, 5, 1)) || '-' ||
                 hex(substr(GuidColumn, 8, 1)) ||
                 hex(substr(GuidColumn, 7, 1)) || '-' ||
                 hex(substr(GuidColumn, 9, 2)) || '-' ||
                 hex(substr(GuidColumn, 11, 6))
WHERE typeof(GuidColumn) == 'blob';

Di EF Core, Anda juga dapat terus menggunakan perilaku sebelumnya dengan mengonfigurasi pengonversi nilai pada properti ini.

modelBuilder
    .Entity<MyEntity>()
    .Property(e => e.GuidProperty)
    .HasConversion(
        g => g.ToByteArray(),
        b => new Guid(b));

Microsoft.Data.Sqlite tetap mampu membaca nilai Guid dari kolom BLOB dan TEXT; namun, karena format default untuk parameter dan konstanta telah berubah, Anda mungkin perlu mengambil tindakan untuk sebagian besar skenario yang melibatkan Guid.

Nilai karakter sekarang disimpan sebagai TEKS di SQLite

Masalah Pelacakan #15020

Perilaku yang lama

Nilai karakter sebelumnya disimpan sebagai nilai BILANGAN BULAT pada SQLite. Misalnya, nilai karakter A disimpan sebagai nilai bilangan bulat 65.

Perilaku yang baru

Nilai karakter sekarang disimpan sebagai TEXT.

Mengapa

Menyimpan nilai karena TEXT lebih alami dan membuat database lebih kompatibel dengan teknologi lain.

Mitigasi

Anda dapat memigrasikan database yang sudah ada ke format baru dengan menjalankan SQL seperti berikut ini.

UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';

Di EF Core, Anda juga dapat terus menggunakan perilaku sebelumnya dengan mengonfigurasi pengonversi nilai pada properti ini.

modelBuilder
    .Entity<MyEntity>()
    .Property(e => e.CharProperty)
    .HasConversion(
        c => (long)c,
        i => (char)i);

Microsoft.Data.Sqlite juga tetap mampu membaca nilai karakter dari kolom INTEGER dan TEXT, sehingga skenario tertentu mungkin tidak memerlukan tindakan apa pun.

ID migrasi sekarang dihasilkan menggunakan kalender budaya invariant

Masalah Pelacakan #12978

Perilaku yang lama

ID migrasi dibuat secara tidak sengaja menggunakan kalender budaya saat ini.

Perilaku yang baru

ID migrasi sekarang selalu dihasilkan menggunakan kalender budaya invariant (Gregorian).

Mengapa

Urutan migrasi penting saat memperbarui database atau menyelesaikan konflik penggabungan. Menggunakan kalender invarian menghindari masalah pemesanan yang dapat diakibatkan oleh anggota tim yang memiliki kalender sistem yang berbeda.

Mitigasi

Perubahan ini mempengaruhi siapa pun yang menggunakan kalender non-Gregorian di mana tahun lebih besar dari kalender Gregorian (seperti kalender Buddha Thailand). ID migrasi yang ada perlu diperbarui sehingga migrasi baru diurutkan setelah migrasi yang ada.

ID migrasi dapat ditemukan di atribut Migrasi dalam file perancang migrasi.

 [DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
 partial class MyMigration
 {

Tabel Riwayat Migrasi juga perlu diperbarui.

UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4)  - 543, SUBSTRING(MigrationId, 4, 150))

UseRowNumberForPaging telah dihapus

Masalah Pelacakan #16400

Perilaku yang lama

Sebelum EF Core 3.0, UseRowNumberForPaging dapat digunakan untuk menghasilkan SQL untuk halaman yang kompatibel dengan SQL Server 2008.

Perilaku yang baru

Dimulai dengan EF Core 3.0, EF hanya akan menghasilkan SQL untuk halaman yang hanya kompatibel dengan versi SQL Server yang lebih baru.

Mengapa

Kami membuat perubahan ini karena SQL Server 2008 bukan lagi produk yang didukung dan memperbarui fitur ini untuk bekerja dengan perubahan kueri yang dibuat di EF Core 3.0 adalah pekerjaan yang signifikan.

Mitigasi

Sebaiknya perbarui ke versi SQL Server yang lebih baru, atau gunakan tingkat kompatibilitas yang lebih tinggi, sehingga SQL yang dihasilkan didukung. Meskipun demikian, jika Anda tidak dapat melakukan ini, silakan komentari masalah pelacakan dengan detail. Kami dapat mengunjungi kembali keputusan ini berdasarkan umpan balik.

Info/metadata ekstensi telah dihapus dari IDbContextOptionsExtension

Masalah Pelacakan #16119

Perilaku yang lama

IDbContextOptionsExtension berisi metode untuk menyediakan metadata tentang ekstensi.

Perilaku yang baru

Metode ini telah dipindahkan ke kelas dasar abstrak baru DbContextOptionsExtensionInfo , yang dikembalikan dari properti baru IDbContextOptionsExtension.Info .

Mengapa

Selama rilis dari 2.0 hingga 3.0 kami perlu menambahkan atau mengubah metode ini beberapa kali. Memecahnya menjadi kelas dasar abstrak baru akan memudahkan untuk membuat perubahan semacam ini tanpa merusak ekstensi yang ada.

Mitigasi

Perbarui ekstensi untuk mengikuti pola baru. Contoh ditemukan dalam banyak implementasi IDbContextOptionsExtension untuk berbagai jenis ekstensi dalam kode sumber EF Core.

LogQueryPossibleExceptionWithAggregateOperator telah diganti namanya

Masalah Pelacakan #10985

Ubah

RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator telah diganti namanya menjadi RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning.

Mengapa

Menyelaraskan penamaan peristiwa peringatan ini dengan semua peristiwa peringatan lainnya.

Mitigasi

Gunakan nama baru. (Perhatikan bahwa nomor ID peristiwa tidak berubah.)

Mengklarifikasi API untuk nama batasan kunci asing

Masalah Pelacakan #10730

Perilaku yang lama

Sebelum EF Core 3.0, nama batasan kunci asing disebut sebagai "nama" saja. Contohnya:

var constraintName = myForeignKey.Name;

Perilaku yang baru

Dimulai dengan EF Core 3.0, nama batasan kunci asing sekarang disebut sebagai "nama batasan". Contohnya:

var constraintName = myForeignKey.ConstraintName;

Mengapa

Perubahan ini membawa konsistensi untuk penamaan di area ini, dan juga mengklarifikasi bahwa ini adalah nama batasan kunci asing, dan bukan nama kolom atau properti tempat kunci asing didefinisikan.

Mitigasi

Gunakan nama baru.

IRelationalDatabaseCreator.HasTables/HasTablesAsync telah dipublikasikan

Masalah Pelacakan #15997

Perilaku yang lama

Sebelum EF Core 3.0, metode ini dilindungi.

Perilaku yang baru

Dimulai dengan EF Core 3.0, metode ini bersifat publik.

Mengapa

Metode ini digunakan oleh EF untuk menentukan apakah database dibuat tetapi kosong. Ini juga dapat berguna dari luar EF saat menentukan apakah akan menerapkan migrasi atau tidak.

Mitigasi

Ubah aksesibilitas penimpaan apa pun.

Microsoft.EntityFrameworkCore.Design sekarang menjadi paket DevelopmentDependency

Masalah Pelacakan #11506

Perilaku yang lama

Sebelum EF Core 3.0, Microsoft.EntityFrameworkCore.Design adalah paket NuGet biasa yang perakitannya dapat direferensikan oleh proyek yang bergantung padanya.

Perilaku yang baru

Dimulai dengan EF Core 3.0, ini adalah paket DevelopmentDependency. Ini berarti bahwa dependensi tidak akan mengalir secara transitif ke proyek lain, dan Anda tidak dapat lagi, secara default, mereferensikan perakitannya.

Mengapa

Paket ini hanya dimaksudkan untuk digunakan pada waktu desain. Aplikasi yang disebarkan tidak boleh mereferensikannya. Membuat paket menjadi DevelopmentDependency memperkuat rekomendasi ini.

Mitigasi

Jika Anda perlu mereferensikan paket ini untuk mengambil alih perilaku waktu desain EF Core, maka Anda dapat memperbarui metadata item PackageReference dalam proyek Anda.

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
  <PrivateAssets>all</PrivateAssets>
  <!-- Remove IncludeAssets to allow compiling against the assembly -->
  <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>

Jika paket direferensikan secara transitif melalui Microsoft.EntityFrameworkCore.Tools, Anda harus menambahkan PackageReference eksplisit ke paket untuk mengubah metadatanya. Referensi eksplisit seperti itu harus ditambahkan ke proyek apa pun di mana jenis dari paket diperlukan.

SQLitePCL.raw diperbarui ke versi 2.0.0

Masalah Pelacakan #14824

Perilaku yang lama

Microsoft.EntityFrameworkCore.Sqlite sebelumnya bergantung pada versi 1.1.12 SQLitePCL.raw.

Perilaku yang baru

Kami telah memperbarui paket kami agar bergantung pada versi 2.0.0.

Mengapa

Versi 2.0.0 dari SQLitePCL.raw menargetkan .NET Standard 2.0. Ini sebelumnya menargetkan .NET Standard 1.1 yang memerlukan penutupan besar paket transitif untuk bekerja.

Mitigasi

SQLitePCL.raw versi 2.0.0 menyertakan beberapa perubahan yang melanggar. Lihat catatan rilis untuk detail lebih lanjut.

NetTopologySuite diperbarui ke versi 2.0.0

Masalah Pelacakan #14825

Perilaku yang lama

Paket spasial sebelumnya bergantung pada NetTopologySuite versi 1.15.1.

Perilaku yang baru

Kami telah memperbarui paket kami agar bergantung pada versi 2.0.0.

Mengapa

NetTopologySuite versi 2.0.0 bertujuan untuk mengatasi beberapa masalah kegunaan yang dihadapi oleh pengguna EF Core.

Mitigasi

NetTopologySuite versi 2.0.0 mencakup beberapa perubahan yang melanggar. Lihat catatan rilis untuk detail lebih lanjut.

Microsoft.Data.SqlClient digunakan alih-alih System.Data.SqlClient

Masalah Pelacakan #15636

Perilaku yang lama

Microsoft.EntityFrameworkCore.SqlServer sebelumnya bergantung pada System.Data.SqlClient.

Perilaku yang baru

Kami telah memperbarui paket agar bergantung pada Microsoft.Data.SqlClient.

Mengapa

Microsoft.Data.SqlClient adalah driver akses data unggulan untuk SQL Server ke depannya, dan System.Data.SqlClient tidak lagi menjadi fokus pengembangan. Beberapa fitur penting, seperti Always Encrypted, hanya tersedia di Microsoft.Data.SqlClient.

Mitigasi

Jika kode Anda mengambil dependensi langsung pada System.Data.SqlClient, Anda harus mengubahnya untuk mereferensikan Microsoft.Data.SqlClient sebagai gantinya; karena kedua paket mempertahankan tingkat kompatibilitas API yang sangat tinggi, ini seharusnya hanya menjadi paket sederhana dan perubahan namespace layanan.

Beberapa hubungan referensi mandiri ambigu harus dikonfigurasi

Masalah Pelacakan #13573

Perilaku yang lama

Jenis entitas dengan beberapa properti navigasi arah uni-arah yang merujuk sendiri dan FK yang cocok salah dikonfigurasi sebagai hubungan tunggal. Contohnya:

public class User
{
        public Guid Id { get; set; }
        public User CreatedBy { get; set; }
        public User UpdatedBy { get; set; }
        public Guid CreatedById { get; set; }
        public Guid? UpdatedById { get; set; }
}

Perilaku yang baru

Skenario ini sekarang terdeteksi dalam pembuatan model dan pengecualian dilemparkan yang menunjukkan bahwa model ambigu.

Mengapa

Model yang dihasilkan ambigu dan kemungkinan akan salah untuk kasus ini.

Mitigasi

Gunakan konfigurasi lengkap hubungan. Contohnya:

modelBuilder
     .Entity<User>()
     .HasOne(e => e.CreatedBy)
     .WithMany();

 modelBuilder
     .Entity<User>()
     .HasOne(e => e.UpdatedBy)
     .WithMany();

DbFunction.Schema menjadi string null atau kosong mengonfigurasinya agar berada dalam skema default model

Masalah Pelacakan #12757

Perilaku yang lama

DbFunction yang dikonfigurasi dengan skema sebagai string kosong diperlakukan sebagai fungsi bawaan tanpa skema. Misalnya kode berikut akan memetakan DatePart fungsi CLR ke DATEPART fungsi bawaan di SqlServer.

[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();

Perilaku yang baru

Semua pemetaan DbFunction dianggap dipetakan ke fungsi yang ditentukan pengguna. Oleh karena itu, nilai string kosong akan menempatkan fungsi di dalam skema default untuk model. Yang bisa menjadi skema yang dikonfigurasi secara eksplisit melalui API modelBuilder.HasDefaultSchema() yang fasih atau dbo sebaliknya.

Mengapa

Skema yang sebelumnya kosong adalah cara untuk memperlakukan fungsi tersebut bawaan tetapi logika itu hanya berlaku untuk SqlServer di mana fungsi bawaan bukan milik skema apa pun.

Mitigasi

Konfigurasikan terjemahan DbFunction secara manual untuk memetakannya ke fungsi bawaan.

modelBuilder
    .HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
    .HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));

EF Core 3.0 menargetkan .NET Standard 2.1 daripada .NET Standard 2.0 Reverted

Masalah Pelacakan #15498

EF Core 3.0 menargetkan .NET Standard 2.1, yang merupakan perubahan mencolok yang mengecualikan aplikasi .NET Framework. EF Core 3.1 mengembalikan ini dan menargetkan .NET Standard 2.0 lagi.

Eksekusi kueri dicatat di tingkat Debug Dikembalikan

Masalah Pelacakan #14523

Kami mengembalikan perubahan ini karena konfigurasi baru di EF Core 3.0 memungkinkan tingkat log untuk setiap peristiwa ditentukan oleh aplikasi. Misalnya, untuk mengalihkan pengelogan SQL ke Debug, secara eksplisit mengonfigurasi tingkat di OnConfiguring atau AddDbContext:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseSqlServer(connectionString)
        .ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));