Bagikan melalui


Meningkatkan aplikasi dari versi sebelumnya ke EF Core 2.0

Kami telah mengambil kesempatan untuk secara signifikan menyempurnakan API dan perilaku kami yang ada di 2.0. Ada beberapa peningkatan yang dapat mengharuskan memodifikasi kode aplikasi yang ada, meskipun kami percaya bahwa untuk sebagian besar aplikasi dampaknya akan rendah, dalam banyak kasus hanya memerlukan kompilasi ulang dan perubahan terpandu minimal untuk mengganti API yang usang.

Memperbarui aplikasi yang ada ke EF Core 2.0 mungkin memerlukan:

  1. Meningkatkan implementasi .NET target aplikasi ke yang mendukung .NET Standard 2.0. Lihat Implementasi .NET yang didukung untuk detail selengkapnya.

  2. Identifikasi penyedia untuk database target yang kompatibel dengan EF Core 2.0. Lihat EF Core 2.0 memerlukan penyedia database 2.0 di bawah ini.

  3. Meningkatkan semua paket EF Core (runtime dan peralatan) ke 2.0. Lihat Menginstal EF Core untuk detail selengkapnya.

  4. Buat perubahan kode yang diperlukan untuk mengkompensasi perubahan yang melanggar yang dijelaskan di sisa dokumen ini.

ASP.NET Core sekarang menyertakan EF Core

Aplikasi yang menargetkan ASP.NET Core 2.0 dapat menggunakan EF Core 2.0 tanpa dependensi tambahan selain penyedia database pihak ketiga. Namun, aplikasi yang menargetkan versi ASP.NET Core sebelumnya perlu ditingkatkan ke ASP.NET Core 2.0 untuk menggunakan EF Core 2.0. Untuk detail selengkapnya tentang meningkatkan aplikasi ASP.NET Core ke 2.0 lihat dokumentasi ASP.NET Core tentang subjek.

Cara baru mendapatkan layanan aplikasi di ASP.NET Core

Pola yang direkomendasikan untuk aplikasi web ASP.NET Core telah diperbarui untuk 2.0 dengan cara yang merusak logika waktu desain EF Core yang digunakan dalam 1.x. Sebelumnya pada waktu desain, EF Core akan mencoba memanggil Startup.ConfigureServices secara langsung untuk mengakses penyedia layanan aplikasi. Dalam ASP.NET Core 2.0, Konfigurasi diinisialisasi di luar Startup kelas. Aplikasi yang menggunakan EF Core biasanya mengakses string koneksi mereka dari Konfigurasi, jadi Startup dengan sendirinya tidak lagi cukup. Jika Anda meningkatkan aplikasi ASP.NET Core 1.x, Anda mungkin menerima kesalahan berikut saat menggunakan alat EF Core.

Tidak ada konstruktor tanpa parameter yang ditemukan di 'ApplicationContext'. Tambahkan konstruktor tanpa parameter ke 'ApplicationContext' atau tambahkan implementasi 'IDesignTimeDbContextFactory<ApplicationContext>' dalam rakitan yang sama dengan 'ApplicationContext'

Kait waktu desain baru telah ditambahkan dalam templat default ASP.NET Core 2.0. Metode statis Program.BuildWebHost memungkinkan EF Core mengakses penyedia layanan aplikasi pada waktu desain. Jika Anda meningkatkan aplikasi ASP.NET Core 1.x, Anda harus memperbarui Program kelas agar menyerupai yang berikut ini.

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace AspNetCoreDotNetCore2._0App
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

Adopsi pola baru ini saat memperbarui aplikasi ke 2.0 sangat disarankan dan diperlukan agar fitur produk seperti Migrasi Inti Kerangka Kerja Entitas berfungsi. Alternatif umum lainnya adalah menerapkan IDesignTimeDbContextFactory TContext>.<

IDbContextFactory diganti namanya

Untuk mendukung pola aplikasi yang beragam dan memberi pengguna kontrol lebih atas bagaimana mereka DbContext digunakan pada waktu desain, kami memiliki, di masa lalu, menyediakan IDbContextFactory<TContext> antarmuka. Pada waktu desain, alat EF Core akan menemukan implementasi antarmuka ini dalam proyek Anda dan menggunakannya untuk membuat DbContext objek.

Antarmuka ini memiliki nama yang sangat umum yang menyesatkan beberapa pengguna untuk mencoba menggunakannya kembali untuk skenario pembuatan lainnya DbContext. Mereka tertangkap lengah ketika Alat EF kemudian mencoba menggunakan implementasi mereka pada waktu desain dan menyebabkan perintah seperti Update-Database atau dotnet ef database update gagal.

Untuk mengomunikasikan semantik waktu desain yang kuat dari antarmuka ini, kami telah mengganti namanya menjadi IDesignTimeDbContextFactory<TContext>.

Untuk rilis IDbContextFactory<TContext> 2.0, masih ada tetapi ditandai sebagai usang.

DbContextFactoryOptions dihapus

Karena perubahan ASP.NET Core 2.0 yang dijelaskan di atas, kami menemukan bahwa itu DbContextFactoryOptions tidak lagi diperlukan pada antarmuka baru IDesignTimeDbContextFactory<TContext> . Berikut adalah alternatif yang harus Anda gunakan sebagai gantinya.

DbContextFactoryOptions Alternatif
ApplicationBasePath AppContext.BaseDirectory
ContentRootPath Directory.GetCurrentDirectory()
EnvironmentName Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")

Direktori kerja waktu desain diubah

Perubahan ASP.NET Core 2.0 juga mengharuskan direktori kerja yang digunakan oleh untuk menyelaraskan dotnet ef dengan direktori kerja yang digunakan oleh Visual Studio saat menjalankan aplikasi Anda. Salah satu efek samping yang dapat diamati dari ini adalah bahwa nama file SQLite sekarang relatif terhadap direktori proyek dan bukan direktori output seperti dulu.

EF Core 2.0 memerlukan penyedia database 2.0

Untuk EF Core 2.0, kami telah membuat banyak penyederhanaan dan peningkatan dalam cara kerja penyedia database. Ini berarti bahwa penyedia 1.0.x dan 1.1.x tidak akan berfungsi dengan EF Core 2.0.

Penyedia SQL Server dan SQLite dikirim oleh tim EF dan versi 2.0 akan tersedia sebagai bagian dari rilis 2.0. Penyedia pihak ketiga sumber terbuka untuk SQL Compact, PostgreSQL, dan MySQL sedang diperbarui untuk 2.0. Untuk semua penyedia lain, silakan hubungi penulis penyedia.

Peristiwa Pengelogan dan Diagnostik telah berubah

Catatan: perubahan ini tidak boleh berdampak pada sebagian besar kode aplikasi.

ID peristiwa untuk pesan yang dikirim ke ILogger telah berubah dalam 2.0. ID peristiwa sekarang unik di seluruh kode EF Core. Pesan tersebut sekarang juga mengikuti pola standar pengelogan terstruktur yang digunakan oleh, misalnya, MVC.

Kategori pencatat juga telah berubah. Sekarang ada serangkaian kategori terkenal yang diakses melalui DbLoggerCategory.

DiagnosticSource peristiwa sekarang menggunakan nama ID peristiwa yang sama dengan pesan yang ILogger sesuai. Payload peristiwa adalah semua jenis nominal yang berasal dari EventData.

ID peristiwa, jenis payload, dan kategori didokumenkan dalam kelas CoreEventId dan RelationalEventId .

ID juga telah dipindahkan dari Microsoft.EntityFrameworkCore.Infrastructure ke namespace Microsoft.EntityFrameworkCore.Diagnostics baru.

Perubahan API metadata relasional EF Core

EF Core 2.0 sekarang akan membangun IModel 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 hubungan umum selalu dilakukan melalui panggilan ke .Relational alih-alih .SqlServer, .Sqlite, dll. Misalnya, kode 1.1.x seperti ini:

var tableName = context.Model.FindEntityType(typeof(User)).SqlServer().TableName;

Sekarang harus ditulis seperti ini:

var tableName = context.Model.FindEntityType(typeof(User)).Relational().TableName;

Alih-alih menggunakan metode seperti ForSqlServerToTable, metode ekstensi sekarang tersedia untuk menulis kode kondisional berdasarkan penyedia saat ini yang digunakan. Contohnya:

modelBuilder.Entity<User>().ToTable(
    Database.IsSqlServer() ? "SqlServerName" : "OtherName");

Perhatikan bahwa perubahan ini hanya berlaku untuk API/metadata yang ditentukan untuk semua penyedia relasional. API dan metadata tetap sama ketika hanya khusus untuk satu penyedia. Misalnya, indeks berkluster khusus untuk SQL Sever, jadi ForSqlServerIsClustered dan .SqlServer().IsClustered() masih harus digunakan.

Jangan mengambil alih penyedia layanan EF

EF Core menggunakan internal IServiceProvider (kontainer injeksi dependensi) untuk implementasi internalnya. Aplikasi harus memungkinkan EF Core untuk membuat dan mengelola penyedia ini kecuali dalam kasus khusus. Sangat mempertimbangkan untuk menghapus panggilan apa pun ke UseInternalServiceProvider. Jika aplikasi memang perlu memanggil UseInternalServiceProvider, pertimbangkan untuk mengajukan masalah sehingga kami dapat menyelidiki cara lain untuk menangani skenario Anda.

AddEntityFrameworkMemanggil , AddEntityFrameworkSqlServer, dll tidak diperlukan oleh kode aplikasi kecuali UseInternalServiceProvider juga dipanggil. Hapus panggilan yang ada ke AddEntityFramework atau AddEntityFrameworkSqlServer, dll. AddDbContext harus tetap digunakan dengan cara yang sama seperti sebelumnya.

Database dalam memori harus diberi nama

Database dalam memori global yang tidak disebutkan namanya telah dihapus dan sebaliknya semua database dalam memori harus diberi nama. Contohnya:

optionsBuilder.UseInMemoryDatabase("MyDatabase");

Ini membuat/menggunakan database dengan nama "MyDatabase". Jika UseInMemoryDatabase dipanggil lagi dengan nama yang sama, database dalam memori yang sama akan digunakan, memungkinkannya dibagikan oleh beberapa instans konteks.

Operasi 'Sertakan' penyedia dalam memori tidak lagi mengembalikan hasil jika navigasi yang disertakan diperlukan tetapi nilainya null

Saat mencoba menyertakan navigasi yang diperlukan dan navigasi yang disertakan null, kueri tidak lagi mengembalikan hasil untuk entitas tempat operasi Sertakan diterapkan. Untuk menghindari masalah ini, berikan nilai untuk navigasi yang diperlukan atau ubah navigasi menjadi opsional.

public class Person
{
    public int Id { get; set; }
    public Language NativeLanguage { get; set;} // required navigation
    public Person Sibling { get; set; } // optional navigation
}
...
var person = new Person();
context.People.Add(person);
await context.SaveChangesAsync();
...

// returns one result
await context.People.ToListAsync();

// returns no results because 'NativeLanguage' navigation is required but has not been provided
await context.People.Include(p => p.NativeLanguage).ToListAsync(); 

// returns one result because 'Sibling' navigation is optional so it doesn't have to be provided
await context.People.Include(p => p.Sibling).ToListAsync();

Perubahan API baca-saja

IsReadOnlyBeforeSave, IsReadOnlyAfterSave, dan IsStoreGeneratedAlways telah usang dan diganti dengan BeforeSaveBehavior dan AfterSaveBehavior. Perilaku ini berlaku untuk properti apa pun (tidak hanya properti yang dihasilkan penyimpanan) dan menentukan bagaimana nilai properti harus digunakan saat menyisipkan ke dalam baris database (BeforeSaveBehavior) atau saat memperbarui baris database yang ada (AfterSaveBehavior).

Properti yang ditandai sebagai ValueGenerated.OnAddOrUpdate (misalnya, untuk kolom komputasi ) secara default akan mengabaikan nilai apa pun yang saat ini diatur pada properti . Ini berarti bahwa nilai yang dihasilkan penyimpanan akan selalu diperoleh terlepas dari apakah nilai apa pun telah ditetapkan atau dimodifikasi pada entitas yang dilacak. Ini dapat diubah dengan mengatur yang berbeda Before\AfterSaveBehavior.

Perilaku penghapusan ClientSetNull baru

Dalam rilis sebelumnya, DeleteBehavior.Restrict memiliki perilaku untuk entitas yang dilacak oleh konteks yang cocok dengan semantik yang lebih tertutup SetNull . Di EF Core 2.0, perilaku baru ClientSetNull telah diperkenalkan sebagai default untuk hubungan opsional. Perilaku ini memiliki SetNull semantik untuk entitas dan Restrict perilaku terlacak untuk database yang dibuat menggunakan EF Core. Dalam pengalaman kami, ini adalah perilaku yang paling diharapkan/berguna untuk entitas terlacak dan database. DeleteBehavior.Restrict sekarang dihormati untuk entitas terlacak saat diatur untuk hubungan opsional.

Paket waktu desain penyedia dihapus

Paket Microsoft.EntityFrameworkCore.Relational.Design telah dihapus. Isinya dikonsolidasikan ke dalam Microsoft.EntityFrameworkCore.Relational dan Microsoft.EntityFrameworkCore.Design.

Ini menyebar ke dalam paket waktu desain penyedia. Paket-paket tersebut (Microsoft.EntityFrameworkCore.Sqlite.Design, Microsoft.EntityFrameworkCore.SqlServer.Design, dll.) dihapus dan kontennya dikonsolidasikan ke dalam paket penyedia utama.

Untuk mengaktifkan Scaffold-DbContext atau dotnet ef dbcontext scaffold di EF Core 2.0, Anda hanya perlu mereferensikan paket penyedia tunggal:

<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer"
    Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools"
    Version="2.0.0"
    PrivateAssets="All" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet"
    Version="2.0.0" />