Bagikan melalui


Memutus perubahan di EF Core 5.0

PERUBAHAN API dan perilaku berikut berpotensi memutus pembaruan aplikasi yang ada ke EF Core 5.0.0.

Ringkasan

Perubahan mencolok Dampak
EF Core 5.0 tidak mendukung .NET Framework Medium
IProperty.GetColumnName() sekarang sudah usang Medium
Presisi dan skala diperlukan untuk desimal Medium
Navigasi yang diperlukan atau tidak dapat diubah ke dependen memiliki semantik yang berbeda Medium
Menentukan kueri diganti dengan metode khusus penyedia Medium
Navigasi referensi non-null tidak ditimpa oleh kueri Medium
ToView() diperlakukan secara berbeda oleh migrasi Medium
ToTable(null) menandai jenis entitas sebagai tidak dipetakan ke tabel Medium
Metode HasGeometricDimension yang dihapus dari ekstensi NTS SQLite Kurang Penting
Azure Cosmos DB: Kunci partisi sekarang ditambahkan ke kunci primer Kurang Penting
Azure Cosmos DB: id properti diganti namanya menjadi __id Kurang Penting
Azure Cosmos DB: byte[] sekarang disimpan sebagai string base64 alih-alih array angka Kurang Penting
Azure Cosmos DB: GetPropertyName dan SetPropertyName diganti namanya Kurang Penting
Generator nilai dipanggil ketika status entitas diubah dari Dilepas menjadi Tidak Berubah, Diperbarui, atau Dihapus Kurang Penting
IMigrationsModelDiffer sekarang menggunakan IRelationalModel Kurang Penting
Diskriminator bersifat baca-saja Kurang Penting
EF khusus penyedia. Metode fungsi dilemparkan untuk penyedia InMemory Kurang Penting
IndexBuilder.HasName sekarang usang Kurang Penting
Pluralizer sekarang disertakan untuk perancah model rekayasa terbalik Kurang Penting
INavigationBase menggantikan INavigation di beberapa API untuk mendukung navigasi lewati Kurang Penting
Beberapa kueri dengan koleksi berkorelasi yang juga menggunakan Distinct atau GroupBy tidak lagi didukung Kurang Penting
Menggunakan kumpulan jenis Yang Dapat Dikueri dalam proyeksi tidak didukung Kurang Penting

Perubahan dampak sedang

EF Core 5.0 tidak mendukung .NET Framework

Masalah Pelacakan #15498

Perilaku yang lama

EF Core 3.1 menargetkan .NET Standard 2.0, yang didukung oleh .NET Framework.

Perilaku yang baru

EF Core 5.0 menargetkan .NET Standard 2.1, yang tidak didukung oleh .NET Framework. Ini berarti EF Core 5.0 tidak dapat digunakan dengan aplikasi .NET Framework.

Mengapa

Ini adalah bagian dari gerakan yang lebih luas di seluruh tim .NET yang bertujuan untuk menyatukan ke satu kerangka kerja target .NET. Untuk informasi selengkapnya, lihat masa depan .NET Standard.

Mitigasi

Aplikasi .NET Framework dapat terus menggunakan EF Core 3.1, yang merupakan rilis dukungan jangka panjang (LTS). Secara bergantian, aplikasi dapat diperbarui untuk menggunakan .NET Core 3.1 atau .NET 5, yang keduanya mendukung .NET Standard 2.1.

IProperty.GetColumnName() sekarang sudah usang

Masalah Pelacakan #2266

Perilaku yang lama

GetColumnName() mengembalikan nama kolom tempat properti dipetakan.

Perilaku yang baru

GetColumnName() masih mengembalikan nama kolom tempat properti dipetakan, tetapi perilaku ini sekarang ambigu karena EF Core 5 mendukung TPT dan pemetaan simultan ke tampilan atau fungsi di mana pemetaan ini dapat menggunakan nama kolom yang berbeda untuk properti yang sama.

Mengapa

Kami menandai metode ini sebagai usang untuk memandu pengguna ke kelebihan beban yang lebih akurat - GetColumnName(IProperty, StoreObjectIdentifier).

Mitigasi

Jika jenis entitas hanya pernah dipetakan ke satu tabel, dan tidak pernah melihat, fungsi, atau beberapa tabel, GetColumnBaseName(IReadOnlyProperty) dapat digunakan dalam EF Core 5.0 dan 6.0 untuk mendapatkan nama tabel. Contohnya:

var columnName = property.GetColumnBaseName();

Dalam EF Core 7.0, ini dapat kembali diganti dengan yang baru GetColumnName, yang berulah seperti yang aslinya untuk pemetaan tabel tunggal sederhana saja.

Jika jenis entitas dapat dipetakan ke tampilan, fungsi, atau beberapa tabel, maka StoreObjectIdentifier harus diperoleh untuk mengidentifikasi tabel, tampilan, atau fungsi. Ini kemudian dapat digunakan untuk mendapatkan nama kolom untuk objek penyimpanan tersebut. Contohnya:

var columnName = property.GetColumnName(StoreObjectIdentifier.Table("Users", null)));

Presisi dan skala diperlukan untuk desimal

Masalah Pelacakan #19293

Perilaku yang lama

EF Core biasanya tidak mengatur presisi dan skala pada SqlParameter objek. Ini berarti presisi dan skala penuh dikirim ke SQL Server, di mana SQL Server akan membulatkan berdasarkan presisi dan skala kolom database.

Perilaku yang baru

EF Core sekarang menetapkan presisi dan skala pada parameter menggunakan nilai yang dikonfigurasi untuk properti dalam model EF Core. Ini berarti pembulatan sekarang terjadi di SqlClient. Akibatnya, jika presisi dan skala yang dikonfigurasi tidak cocok dengan presisi dan skala database, maka pembulatan yang terlihat dapat berubah.

Mengapa

Fitur SQL Server yang lebih baru, termasuk Always Encrypted, mengharuskan aspek parameter ditentukan sepenuhnya. Selain itu, SqlClient membuat perubahan untuk membulatkan alih-alih memotong nilai desimal, sehingga cocok dengan perilaku SQL Server. Ini memungkinkan EF Core untuk mengatur faset ini tanpa mengubah perilaku untuk desimal yang dikonfigurasi dengan benar.

Mitigasi

Petakan properti desimal Anda menggunakan nama jenis yang menyertakan presisi dan skala. Contohnya:

public class Blog
{
    public int Id { get; set; }

    [Column(TypeName = "decimal(16, 5)")]
    public decimal Score { get; set; }
}

Atau gunakan HasPrecision dalam API pembuatan model. Contohnya:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().Property(e => e.Score).HasPrecision(16, 5);
    }

Navigasi yang diperlukan atau tidak dapat diubah ke dependen memiliki semantik yang berbeda

Masalah Pelacakan #17286

Perilaku yang lama

Hanya navigasi ke prinsipal yang dapat dikonfigurasi sesuai kebutuhan. Oleh karena itu, menggunakan RequiredAttribute navigasi ke dependen (entitas yang berisi kunci asing) atau menandainya sebagai non-nullable akan membuat kunci asing pada jenis entitas yang menentukan.

Perilaku yang baru

Dengan dukungan tambahan untuk dependen yang diperlukan, sekarang dimungkinkan untuk menandai navigasi referensi apa pun sesuai kebutuhan, yang berarti bahwa dalam kasus yang ditunjukkan di atas kunci asing akan didefinisikan di sisi lain hubungan dan properti tidak akan ditandai sebagaimana diperlukan.

IsRequired Memanggil sebelum menentukan akhir dependen sekarang ambigu:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .IsRequired()
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey);

Mengapa

Perilaku baru diperlukan untuk mengaktifkan dukungan untuk dependen yang diperlukan (lihat #12100).

Mitigasi

Hapus RequiredAttribute dari navigasi ke dependen dan letakkan pada navigasi ke prinsipal atau konfigurasikan hubungan di OnModelCreating:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey)
    .IsRequired();

Menentukan kueri diganti dengan metode khusus penyedia

Masalah Pelacakan #18903

Perilaku yang lama

Jenis entitas dipetakan untuk menentukan kueri di tingkat Inti. Kapan saja jenis entitas digunakan di akar kueri jenis entitas digantikan oleh kueri yang menentukan untuk penyedia apa pun.

Perilaku yang baru

API untuk menentukan kueri tidak digunakan lagi. API khusus penyedia baru diperkenalkan.

Mengapa

Saat menentukan kueri diimplementasikan sebagai kueri pengganti setiap kali akar kueri digunakan dalam kueri, kueri memiliki beberapa masalah:

  • Jika menentukan kueri memproyeksikan jenis entitas menggunakan new { ... } dalam Select metode, maka mengidentifikasi bahwa sebagai entitas memerlukan pekerjaan tambahan dan membuatnya tidak konsisten dengan bagaimana EF Core memperlakukan jenis nominal dalam kueri.
  • Untuk penyedia FromSql relasional masih diperlukan untuk meneruskan string SQL dalam formulir ekspresi LINQ.

Awalnya menentukan kueri diperkenalkan sebagai tampilan sisi klien yang akan digunakan dengan penyedia In-Memory untuk entitas tanpa kunci (mirip dengan tampilan database dalam database relasional). Definisi tersebut memudahkan pengujian aplikasi terhadap database dalam memori. Setelah itu mereka menjadi berlaku secara luas, yang berguna tetapi membawa perilaku yang tidak konsisten dan sulit dipahami. Jadi kami memutuskan untuk menyederhanakan konsep. Kami membuat kueri penentuan berbasis LINQ eksklusif untuk penyedia In-Memory dan memperlakukannya secara berbeda. Untuk informasi selengkapnya, lihat masalah ini.

Mitigasi

Untuk penyedia relasional, gunakan ToSqlQuery metode masuk OnModelCreating dan teruskan string SQL untuk digunakan untuk jenis entitas. Untuk penyedia Dalam Memori, gunakan ToInMemoryQuery metode di OnModelCreating dan teruskan kueri LINQ untuk digunakan untuk jenis entitas.

Navigasi referensi non-null tidak ditimpa oleh kueri

Masalah Pelacakan #2693

Perilaku yang lama

Dalam EF Core 3.1, navigasi referensi yang dengan bersemangat diinisialisasi ke nilai non-null terkadang akan ditimpa oleh instans entitas dari database, terlepas dari apakah nilai kunci cocok atau tidak. Namun, dalam kasus lain, EF Core 3.1 akan melakukan kebalikannya dan meninggalkan nilai non-null yang ada.

Perilaku yang baru

Dimulai dengan EF Core 5.0, navigasi referensi non-null tidak pernah ditimpa oleh instans yang dikembalikan dari kueri.

Perhatikan bahwa inisialisasi bersemangat navigasi koleksi ke koleksi kosong masih didukung.

Mengapa

Inisialisasi properti navigasi referensi ke instans entitas "kosong" menghasilkan status ambigu. Contohnya:

public class Blog
{
     public int Id { get; set; }
     public Author Author { get; set; ) = new Author();
}

Biasanya kueri untuk Blog dan Penulis akan terlebih dahulu membuat Blog instans lalu mengatur instans yang sesuai Author berdasarkan data yang dikembalikan dari database. Namun, dalam hal ini setiap Blog.Author properti sudah diinisialisasi ke kosong Author. Kecuali EF Core tidak memiliki cara untuk mengetahui bahwa instans ini "kosong". Jadi menimpa instans ini berpotensi secara diam-diam membuang Author. Oleh karena itu, EF Core 5.0 sekarang secara konsisten tidak menimpa navigasi yang sudah diinisialisasi.

Perilaku baru ini juga selaras dengan perilaku EF6 dalam banyak kasus, meskipun setelah diselidiki, kami juga menemukan beberapa kasus inkonsistensi di EF6.

Mitigasi

Jika jeda ini ditemui, maka perbaikannya adalah berhenti menginisialisasi properti navigasi referensi dengan bersemangat.

ToView() diperlakukan secara berbeda oleh migrasi

Masalah Pelacakan #2725

Perilaku yang lama

ToView(string) Panggilan membuat migrasi mengabaikan jenis entitas selain memetakannya ke tampilan.

Perilaku yang baru

Sekarang ToView(string) menandai jenis entitas sebagai tidak dipetakan ke tabel selain memetakannya ke tampilan. Ini menghasilkan migrasi pertama setelah meningkatkan ke EF Core 5 untuk mencoba menghilangkan tabel default untuk jenis entitas ini karena tidak lagi diabaikan.

Mengapa

EF Core sekarang memungkinkan jenis entitas untuk dipetakan ke tabel dan tampilan secara bersamaan, jadi ToView bukan lagi indikator yang valid bahwa itu harus diabaikan oleh migrasi.

Mitigasi

Gunakan kode berikut untuk menandai tabel yang dipetakan sebagai dikecualikan dari migrasi:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().ToTable("UserView", t => t.ExcludeFromMigrations());
}

ToTable(null) menandai jenis entitas sebagai tidak dipetakan ke tabel

Masalah Pelacakan #21172

Perilaku yang lama

ToTable(null) akan mengatur ulang nama tabel ke default.

Perilaku yang baru

ToTable(null) sekarang menandai jenis entitas sebagai tidak dipetakan ke tabel apa pun.

Mengapa

EF Core sekarang memungkinkan jenis entitas untuk dipetakan ke tabel dan tampilan secara bersamaan, jadi ToTable(null) digunakan untuk menunjukkan bahwa itu tidak dipetakan ke tabel apa pun.

Mitigasi

Gunakan kode berikut untuk mereset nama tabel ke default jika tidak dipetakan ke tampilan atau DbFunction:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().Metadata.RemoveAnnotation(RelationalAnnotationNames.TableName);
}

Perubahan berdampak rendah

Metode HasGeometricDimension yang dihapus dari ekstensi NTS SQLite

Masalah Pelacakan #14257

Perilaku yang lama

HasGeometricDimension digunakan untuk mengaktifkan dimensi tambahan (Z dan M) pada kolom geometri. Namun, itu hanya pernah mempengaruhi pembuatan database. Tidak perlu menentukannya untuk mengkueri nilai dengan dimensi tambahan. Ini juga tidak berfungsi dengan benar saat menyisipkan atau memperbarui nilai dengan dimensi tambahan (lihat #14257).

Perilaku yang baru

Untuk mengaktifkan menyisipkan dan memperbarui nilai geometri dengan dimensi tambahan (Z dan M), dimensi perlu ditentukan sebagai bagian dari nama jenis kolom. API ini lebih cocok dengan perilaku yang mendasar dari fungsi AddGeometryColumn SpatiaLite.

Mengapa

Menggunakan HasGeometricDimension setelah menentukan dimensi dalam jenis kolom tidak perlu dan berlebihan, jadi kami menghapus HasGeometricDimension sepenuhnya.

Mitigasi

Gunakan HasColumnType untuk menentukan dimensi:

modelBuilder.Entity<GeoEntity>(
    x =>
    {
        // Allow any GEOMETRY value with optional Z and M values
        x.Property(e => e.Geometry).HasColumnType("GEOMETRYZM");

        // Allow only POINT values with an optional Z value
        x.Property(e => e.Point).HasColumnType("POINTZ");
    });

Azure Cosmos DB: Kunci partisi sekarang ditambahkan ke kunci primer

Masalah Pelacakan #15289

Perilaku yang lama

Properti kunci partisi hanya ditambahkan ke kunci alternatif yang menyertakan id.

Perilaku yang baru

Properti kunci partisi sekarang juga ditambahkan ke kunci utama menurut konvensi.

Mengapa

Perubahan ini membuat model lebih selaras dengan semantik Azure Cosmos DB dan meningkatkan performa Find dan beberapa kueri.

Mitigasi

Untuk mencegah properti kunci partisi ditambahkan ke kunci utama, konfigurasikan di OnModelCreating.

modelBuilder.Entity<Blog>()
    .HasKey(b => b.Id);

Azure Cosmos DB: id properti diganti namanya menjadi __id

Masalah Pelacakan #17751

Perilaku yang lama

Properti bayangan yang dipetakan ke id properti JSON juga diberi nama id.

Perilaku yang baru

Properti bayangan yang dibuat oleh konvensi sekarang bernama __id.

Mengapa

Perubahan ini membuatnya lebih kecil kemungkinan properti id berbenturan dengan properti yang ada pada jenis entitas.

Mitigasi

Untuk kembali ke perilaku 3.x, konfigurasikan id properti di OnModelCreating.

modelBuilder.Entity<Blog>()
    .Property<string>("id")
    .ToJsonProperty("id");

Azure Cosmos DB: byte[] sekarang disimpan sebagai string base64 alih-alih array angka

Masalah Pelacakan #17306

Perilaku yang lama

Properti tipe byte[] disimpan sebagai array angka.

Perilaku yang baru

Properti jenis byte[] sekarang disimpan sebagai string base64.

Mengapa

Representasi byte[] ini selaras lebih baik dengan ekspektasi dan merupakan perilaku default pustaka serialisasi JSON utama.

Mitigasi

Data yang ada disimpan sebagai array angka masih akan dikueri dengan benar, tetapi saat ini tidak ada cara yang didukung untuk mengubah kembali perilaku penyisipan. Jika batasan ini memblokir skenario Anda, komentari masalah ini

Azure Cosmos DB: GetPropertyName dan SetPropertyName diganti namanya

Masalah Pelacakan #17874

Perilaku yang lama

Sebelumnya metode ekstensi dipanggil GetPropertyName dan SetPropertyName

Perilaku yang baru

API lama dihapus dan metode baru ditambahkan: GetJsonPropertyName, SetJsonPropertyName

Mengapa

Perubahan ini menghapus ambiguitas sekeliling metode ini yang dikonfigurasi.

Mitigasi

Gunakan API baru.

Generator nilai dipanggil ketika status entitas diubah dari Dilepas menjadi Tidak Berubah, Diperbarui, atau Dihapus

Masalah Pelacakan #15289

Perilaku yang lama

Generator nilai hanya dipanggil ketika status entitas berubah menjadi Ditambahkan.

Perilaku yang baru

Generator nilai sekarang dipanggil ketika status entitas diubah dari Dilepas menjadi Tidak Berubah, Diperbarui, atau Dihapus dan properti berisi nilai default.

Mengapa

Perubahan ini diperlukan untuk meningkatkan pengalaman dengan properti yang tidak bertahan ke penyimpanan data dan nilainya selalu dihasilkan pada klien.

Mitigasi

Untuk mencegah generator nilai dipanggil, tetapkan nilai non-default ke properti sebelum status diubah.

IMigrationsModelDiffer sekarang menggunakan IRelationalModel

Masalah Pelacakan #20305

Perilaku yang lama

IMigrationsModelDiffer API didefinisikan menggunakan IModel.

Perilaku yang baru

IMigrationsModelDiffer API sekarang menggunakan IRelationalModel. Namun rekam jepret model masih hanya IModel berisi karena kode ini adalah bagian dari aplikasi dan Kerangka Kerja Entitas tidak dapat mengubahnya tanpa membuat perubahan yang melanggar yang lebih besar.

Mengapa

IRelationalModel adalah representasi yang baru ditambahkan dari skema database. Menggunakannya untuk menemukan perbedaan lebih cepat dan lebih akurat.

Mitigasi

Gunakan kode berikut untuk membandingkan model dari snapshot dengan model dari context:

var dependencies = context.GetService<ProviderConventionSetBuilderDependencies>();
var relationalDependencies = context.GetService<RelationalConventionSetBuilderDependencies>();

var typeMappingConvention = new TypeMappingConvention(dependencies);
typeMappingConvention.ProcessModelFinalizing(((IConventionModel)modelSnapshot.Model).Builder, null);

var relationalModelConvention = new RelationalModelConvention(dependencies, relationalDependencies);
var sourceModel = relationalModelConvention.ProcessModelFinalized(snapshot.Model);

var modelDiffer = context.GetService<IMigrationsModelDiffer>();
var hasDifferences = modelDiffer.HasDifferences(
    ((IMutableModel)sourceModel).FinalizeModel().GetRelationalModel(),
    context.Model.GetRelationalModel());

Kami berencana untuk meningkatkan pengalaman ini di 6.0 (lihat #22031)

Diskriminator bersifat baca-saja

Masalah Pelacakan #21154

Perilaku yang lama

Dimungkinkan untuk mengubah nilai diskriminator sebelum memanggil SaveChanges

Perilaku yang baru

Pengecualian akan dilemparkan dalam kasus di atas.

Mengapa

EF tidak mengharapkan jenis entitas berubah saat masih dilacak, jadi mengubah nilai diskriminator meninggalkan konteks dalam keadaan tidak konsisten, yang mungkin mengakibatkan perilaku yang tidak terduga.

Mitigasi

Jika mengubah nilai diskriminator diperlukan dan konteks akan segera dibuang setelah memanggil SaveChanges, diskriminator dapat dibuat dapat diubah:

modelBuilder.Entity<BaseEntity>()
    .Property<string>("Discriminator")
    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);

EF khusus penyedia. Metode fungsi dilemparkan untuk penyedia InMemory

Masalah Pelacakan #20294

Perilaku yang lama

EF khusus penyedia. Metode Functions berisi implementasi untuk eksekusi klien, yang memungkinkan mereka untuk dijalankan pada penyedia InMemory. Misalnya, EF.Functions.DateDiffDay adalah metode khusus Sql Server, yang bekerja pada penyedia InMemory.

Perilaku yang baru

Metode khusus penyedia telah diperbarui untuk melemparkan pengecualian dalam isi metode mereka untuk memblokir evaluasi mereka di sisi klien.

Mengapa

Metode khusus penyedia dipetakan ke fungsi database. Komputasi yang dilakukan oleh fungsi database yang dipetakan tidak selalu dapat direplikasi di sisi klien di LINQ. Ini dapat menyebabkan hasil dari server berbeda saat menjalankan metode yang sama pada klien. Karena metode ini digunakan dalam LINQ untuk diterjemahkan ke fungsi database tertentu, metode ini tidak perlu dievaluasi di sisi klien. Karena penyedia InMemory adalah database yang berbeda, metode ini tidak tersedia untuk penyedia ini. Mencoba mengeksekusinya untuk penyedia InMemory, atau penyedia lain yang tidak menerjemahkan metode ini, memberikan pengecualian.

Mitigasi

Karena tidak ada cara untuk menimpulkan perilaku fungsi database secara akurat, Anda harus menguji kueri yang berisinya terhadap jenis database yang sama seperti dalam produksi.

IndexBuilder.HasName sekarang usang

Masalah Pelacakan #21089

Perilaku yang lama

Sebelumnya, hanya satu indeks yang dapat didefinisikan melalui sekumpulan properti tertentu. Nama database indeks dikonfigurasi menggunakan IndexBuilder.HasName.

Perilaku yang baru

Beberapa indeks sekarang diizinkan pada set atau properti yang sama. Indeks-indeks ini sekarang dibedakan oleh nama dalam model. Menurut konvensi, nama model digunakan sebagai nama database; namun juga dapat dikonfigurasi secara independen menggunakan HasDatabaseName.

Mengapa

Di masa mendatang, kami ingin mengaktifkan indeks atau indeks naik dan turun dengan kolase yang berbeda pada kumpulan properti yang sama. Perubahan ini memindahkan kita langkah lain ke arah itu.

Mitigasi

Kode apa pun yang sebelumnya memanggil IndexBuilder.HasName harus diperbarui untuk memanggil HasDatabaseName sebagai gantinya.

Jika proyek Anda menyertakan migrasi yang dihasilkan sebelum EF Core versi 2.0.0, Anda dapat dengan aman mengabaikan peringatan dalam file-file tersebut dan menekannya dengan menambahkan #pragma warning disable 612, 618.

Pluralizer sekarang disertakan untuk perancah model rekayasa terbalik

Masalah Pelacakan #11160

Perilaku yang lama

Sebelumnya, Anda harus menginstal paket pluralizer terpisah untuk menetralisasi DbSet dan mengumpulkan nama navigasi dan menyelaraskan nama tabel saat membuat perancah DbContext dan jenis entitas dengan merekayasa balik skema database.

Perilaku yang baru

EF Core sekarang menyertakan pluralizer yang menggunakan pustaka Humanizer . Ini adalah pustaka yang sama yang digunakan Visual Studio untuk merekomendasikan nama variabel.

Mengapa

Menggunakan bentuk kata jamak untuk properti koleksi dan bentuk tunggal untuk jenis dan properti referensi idiomatik di .NET.

Mitigasi

Untuk menonaktifkan pluralizer, gunakan --no-pluralize opsi aktif dotnet ef dbcontext scaffold atau -NoPluralize tombol aktifkan Scaffold-DbContext.

INavigationBase menggantikan INavigation di beberapa API untuk mendukung navigasi lewati

Masalah Pelacakan #2568

Perilaku yang lama

EF Core sebelum 5.0 hanya mendukung satu bentuk properti navigasi, yang INavigation diwakili oleh antarmuka.

Perilaku yang baru

EF Core 5.0 memperkenalkan hubungan banyak ke banyak yang menggunakan "lewati navigasi". Ini diwakili oleh ISkipNavigation antarmuka, dan sebagian besar fungsionalitas INavigation telah didorong ke antarmuka dasar umum: INavigationBase.

Mengapa

Sebagian besar fungsionalitas antara navigasi normal dan lewati sama. Namun, navigasi lewati memiliki hubungan yang berbeda dengan kunci asing daripada navigasi normal, karena FK yang terlibat tidak langsung di salah satu akhir hubungan, melainkan di entitas gabungan.

Mitigasi

Dalam banyak kasus, aplikasi dapat beralih menggunakan antarmuka dasar baru tanpa perubahan lain. Namun, dalam kasus di mana navigasi digunakan untuk mengakses properti kunci asing, kode aplikasi harus dibatasi hanya untuk navigasi normal, atau diperbarui untuk melakukan hal yang sesuai untuk navigasi normal dan lewati.

Beberapa kueri dengan koleksi berkorelasi yang juga menggunakan Distinct atau GroupBy tidak lagi didukung

Masalah Pelacakan #15873

Perilaku lama

Sebelumnya, kueri yang melibatkan koleksi berkorelasi diikuti oleh GroupBy, serta beberapa kueri menggunakan Distinct kami diizinkan untuk mengeksekusi.

Contoh GroupBy:

context.Parents
    .Select(p => p.Children
        .GroupBy(c => c.School)
        .Select(g => g.Key))

Distinct contoh - khususnya Distinct kueri di mana proyeksi pengumpulan dalam tidak berisi kunci utama:

context.Parents
    .Select(p => p.Children
        .Select(c => c.School)
        .Distinct())

Kueri ini dapat mengembalikan hasil yang salah jika koleksi dalam berisi duplikat apa pun, tetapi berfungsi dengan benar jika semua elemen dalam koleksi dalam unik.

Perilaku baru

Kueri ini tidak lagi didukung. Pengecualian dilemparkan menunjukkan bahwa kami tidak memiliki informasi yang cukup untuk membangun hasil dengan benar.

Mengapa

Untuk skenario pengumpulan yang berkorelasi, kita perlu mengetahui kunci utama entitas untuk menetapkan entitas pengumpulan ke induk yang benar. Ketika koleksi dalam tidak menggunakan GroupBy atau Distinct, kunci primer yang hilang hanya dapat ditambahkan ke proyeksi. Namun dalam kasus GroupBy dan Distinct tidak dapat dilakukan karena akan mengubah hasil GroupBy atau Distinct operasi.

Mitigasi

Tulis ulang kueri untuk tidak menggunakan GroupBy atau Distinct operasi pada koleksi dalam, dan lakukan operasi ini pada klien sebagai gantinya.

context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.GroupBy(c => c).Select(g => g.Key))
context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.Distinct())

Menggunakan kumpulan jenis Yang Dapat Dikueri dalam proyeksi tidak didukung

Masalah Pelacakan #16314

Perilaku lama

Sebelumnya, dimungkinkan untuk menggunakan kumpulan jenis Yang Dapat Dikueri di dalam proyeksi dalam beberapa kasus, misalnya sebagai argumen ke List<T> konstruktor:

context.Blogs
    .Select(b => new List<Post>(context.Posts.Where(p => p.BlogId == b.Id)))

Perilaku baru

Kueri ini tidak lagi didukung. Pengecualian dilemparkan menunjukkan bahwa kita tidak dapat membuat objek jenis Yang Dapat Dikueri dan menyarankan bagaimana hal ini dapat diperbaiki.

Mengapa

Kami tidak dapat mewujudkan objek dari jenis Yang Dapat Dikueri, sehingga objek tersebut akan dibuat secara otomatis menggunakan List<T> jenis sebagai gantinya. Ini sering menyebabkan pengecualian karena ketidakcocokan jenis yang tidak terlalu jelas dan bisa mengejutkan beberapa pengguna. Kami memutuskan untuk mengenali pola dan melemparkan pengecualian yang lebih bermakna.

Mitigasi

Tambahkan ToList() panggilan setelah objek Yang Dapat Dikueri dalam proyeksi:

context.Blogs.Select(b => context.Posts.Where(p => p.BlogId == b.Id).ToList())