Teknologi WarisanPeringatan: ASP.NET MVC sudah usang. Dianjurkan untuk menggunakan ASP.NET Core. Tetapi jika Anda tertarik, maka bacalah.
Saya memutuskan untuk sedikit memperluas
artikel sebelumnya tentang ASP.NET MVC dan MySQL . Itu tentang bekerja dengan MySQL di ASP.NET MVC bukan melalui ORM Entity Framework (EF) yang hampir standar, tetapi menggunakan akses langsung ke DBMS melalui ADO.NET. Dan implementasi metode akses ini diberikan. Dan meskipun metode ini sudah usang dan tidak direkomendasikan untuk digunakan, kadang-kadang berguna: misalnya, dalam aplikasi yang sangat dimuat atau ketika pengembang dihadapkan pada situasi di mana ORM tidak dapat menghasilkan kueri SQL yang berfungsi dengan benar. Dan kadang-kadang Anda dapat menggabungkan kedua metode dalam aplikasi - baik melalui ORM dan melalui ADO.NET. Akibatnya, saya berpikir dan memutuskan untuk menyelesaikan aplikasi: menambahkan implementasi repositori untuk Kerangka Entitas ke dalamnya dan membuat pilihan mereka bergantung pada parameter aplikasi menggunakan Penyelesai Ketergantungan.
Semua kode dapat diambil di sini di
alamat ini , di bawah kode ini akan disajikan sebagian dengan tautan kecil dan penjelasan sehubungan dengan
proyek sebelumnya . Dan di sini Anda dapat
melihat aplikasinya .
Kami mengubah proyek
1. Untuk menggunakan Entity Framework dengan MySQL, kita perlu menginstal pustaka
MySQL.Data.EntityFramework (Anda tentu saja dapat memiliki yang lain, hanya saja ini dari Oracle, pemilik MySQL).

Ini akan menarik
MySQL.Data dan
EntityFramework itu sendiri . Perubahan berikut dibuat pada
file web.config :
<entityFramework> <providers> <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.EntityFramework, Version=8.0.19.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /> </providers> </entityFramework>
Konflik yang menarik muncul dengan
MySQL.Data - karena
MySQL.Data.EntityFramework memerlukan versi
MySQL.Data minimal 8.0.19, itu diperbarui ... dan proyek berhenti bekerja. Kesalahan mulai terjadi:

«Ubiety.Dns.Core» . . , , . ( HRESULT: 0x80131045)
Rupanya,
perakitan yang tidak ditandatangani Ubiety.Dns.Core ditambahkan ke
MySQL.Data 8.0.19 . Saya juga harus memasukkan komponen ini melalui Nuget dalam proyek. Kesalahan hilang.
2. Selain itu, untuk mengimplementasikan implementasi dependensi, kami menambah proyek Ninject - wadah untuk mengimplementasikan dependensi (DI).
3. Kami akan sedikit mengubah struktur proyek: kami akan menempatkan file repositori ke dalam direktori
Repositori terpisah dan membuat subdirektori
ADO.NET di dalamnya (kami akan mentransfer file
LanguagesRepository.cs dan
UsersRepository.cs yang ada di sana ) dan
EF (akan ada file repositori untuk Entity Framework di sini).
4. Selain itu, parameter aplikasi telah ditambahkan ke
file web.config di bagian
appConfig
:
<add key="ConnectionMethod" value="ADO.NET" />
. Aplikasi akan mengambil dua nilai: "Entity Framework" atau "ADO.NET".
Menambahkan tautan ke parameter ini ke file
Base.cs :
public static string ConnectionMethod { get { return System.Configuration.ConfigurationManager.AppSettings["ConnectionMethod"]; } }
Entity Framework dan MySQL - repository
Tambahkan file
DbContext.cs dengan kelas
EFDbContext
ke
EFDbContext
Repository \ EF :
public class EFDbContext : DbContext { public EFDbContext() : base(Base.ConnectionString) { } public DbSet<UserClass> Users { get; set; } public DbSet<LanguageClass> Languages { get; set; } }
Di dalamnya, kami menentukan string koneksi DBMS yang digunakan dan set data
Users
dan
Languages
.
Tambahkan file
LanguagesRepository.cs dengan kelas
LanguagesRepositoryEF
:
public class LanguagesRepositoryEF : ILanguagesRepository { private EFDbContext context = new EFDbContext(); public IList<LanguageClass> List() { return context.Languages.OrderBy(x => x.LanguageName).ToList(); } }
Dan file
UsersRepository.cs dengan kelas
UsersRepositoryEF
:
public class UsersRepositoryEF : IUsersRepository { private EFDbContext context = new EFDbContext(); public IList<UserClass> List() { return context.Users.ToList(); } public IList<UserClass> List(string sortName, SortDirection sortDir, int page, int pageSize, out int count) { count = context.Users.Count(); if (sortName != null) return context.Users.OrderByDynamic(sortName, sortDir).Skip((page - 1) * pageSize).Take(pageSize).ToList(); else return context.Users.OrderBy(o => o.UserID).Skip((page - 1) * pageSize).Take(pageSize).ToList(); } public bool AddUser(UserClass user) { user.Language = context.Languages.Find(user.Language.LanguageID); if (user.Language != null && context.Users.Add(user) != null) { try { context.SaveChanges(); } catch (System.Exception ex) {} } return user.UserID > 0; } public UserClass FetchByID(int userID) { UserClass user = null; try { user = context.Users.Find(userID); } catch (System.Exception ex) { } return user; } public bool ChangeUser(UserClass user) { bool result = false; user.Language = context.Languages.Find(user.Language.LanguageID); if (user.Language != null) { UserClass olduser = context.Users.Find(user.UserID); if (olduser != null) { olduser.Email = user.Email; olduser.Loginname = user.Loginname; olduser.Language = user.Language; olduser.SupporterTier = user.SupporterTier; try { result = context.SaveChanges() > 0; } catch (System.Exception ex) { } } } return result; } public bool RemoveUser(UserClass user) { bool result = false; UserClass olduser = context.Users.Find(user.UserID); if (olduser != null) context.Users.Remove(olduser); try { result = context.SaveChanges() > 0; } catch (System.Exception ex) { } return result; } }
Dapat dilihat bahwa ukuran file jelas lebih pendek dari itu untuk ADO.NET - ORM melakukan pekerjaan kotor untuk kami - ia menciptakan query SQL sendiri.
Namun, saya menemukan beberapa poin yang masuk ke dalam implementasi ADO.NET, tetapi tidak berhasil di EF.
Hal pertama yang saya harus lakukan untuk mengubah file
UserClass.cs (dalam direktori
Domain ): tambahkan bidang lain untuk operasi normal koneksi antara tabel
Users
dan
Languages
:
[HiddenInput(DisplayValue = false)] public int? LanguageID { get; set; }
Dan yang kedua - ternyata bidang di MySQL seperti
Enum
tidak bekerja melalui EF. Kemungkinan besar, alasan untuk ini adalah bahwa enumerasi dalam kode adalah nilai integer, tetapi dari database nilai-nilai melalui EF dibaca sebagai teks (jika dalam query dari MySQL untuk membaca nilai-nilai bidang tipe enum MySQL mengembalikan hanya nilai teks dari enumerasi ini). Dan jika dalam versi untuk ADO.NET saya dapat menyiasati hal ini menggunakan
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
konstruksi
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
, kemudian dengan EF metamorfosis seperti itu ternyata tidak dapat diatasi bagi saya - tidak ada opsi yang dicoba muncul. Nah, karena teknologi
Code First menghasilkan bidang tipe
Enum
sebagai bidang tipe INT, kami harus mengubah jenis bidang
SupporterTier
dalam database:
CHANGE COLUMN `SupporterTier` `SupporterTier` INT(4) UNSIGNED NOT NULL DEFAULT '1' ;
Pilih repositori menggunakan parameter aplikasi
Kami akan menggunakan implementasi melalui konstruktor, seperti yang tertulis di buku teks. Pertama, kita perlu membuat antarmuka untuk repositori bersama kita: membuat file
LanguagesRepository.cs di direktori
Repositori dengan konten:
public interface ILanguagesRepository { IList<LanguageClass> List(); }
Dan file
UsersRepository.cs dengan konten:
public interface IUsersRepository { IList<UserClass> List(); IList<UserClass> List(string sortName, SortDirection sortDir, int page, int pageSize, out int count); bool AddUser(UserClass user); UserClass FetchByID(int userID); bool ChangeUser(UserClass user); bool RemoveUser(UserClass user); }
Kami mewarisi kelas yang sesuai dari antarmuka ini:
public class LanguagesRepositoryADO : ILanguagesRepository public class UsersRepositoryADO : IUsersRepository public class LanguagesRepositoryEF : ILanguagesRepository public class UsersRepositoryEF : IUsersRepository
Nah, pada pengontrol
UsersController, kami membuat tambahan yang memungkinkannya bekerja dengan antarmuka ini:
private ILanguagesRepository repLanguages; private IUsersRepository repUsers; public UsersController(ILanguagesRepository langsParam, IUsersRepository usersParam) { repLanguages = langsParam; repUsers = usersParam; }
Dan di controller, kami mengubah tempat-tempat mengakses objek kelas-kelas ini ke objek
repLanguages
dan
repUsers
, masing-masing. Tetapi kita perlu melewatkan instance dari kelas repositori melalui konstruktor controller, yang, tentu saja, tidak nyaman. Untuk menghindarinya, kita membutuhkan ilmu sihir yang kuat seperti
Dependency Resolver (DR). Dan untuk ini kita akan menggunakan Ninject:
Kami mendaftarkan DR di file
Global.asax.cs dalam metode
Application_Start
:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
Buat file
NinjectDependencyResolver.cs di direktori
Infrastruktur dengan kelas
NinjectDependencyResolver
(diwarisi dari antarmuka
IDependencyResolver
):
public class NinjectDependencyResolver : IDependencyResolver { private IKernel kernel; public NinjectDependencyResolver() { kernel = new StandardKernel(); AddBindings(); } public object GetService(Type serviceType) { return kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return kernel.GetAll(serviceType); } private void AddBindings() { if (Domain.Base.ConnectionMethod == "Entity Framework") { kernel.Bind<ILanguagesRepository>().To<LanguagesRepositoryEF>(); kernel.Bind<IUsersRepository>().To<UsersRepositoryEF>(); } else { kernel.Bind<ILanguagesRepository>().To<LanguagesRepositoryADO>(); kernel.Bind<IUsersRepository>().To<UsersRepositoryADO>(); } } }
Dan ternyata satu-satunya tempat di mana ditentukan metode mana yang bekerja dengan DBMS digunakan (langsung, melalui ADO.NET atau melalui Entity Framework) adalah metode
AddBindings
di kelas
NinjectDependencyResolver
. Sihir sungguhan jika Anda tidak tahu cara kerjanya.
Dalam metode
AddBindings
, tergantung pada nilai parameter aplikasi ConnectionMethod,
IUsersRepository
dan
IUsersRepository
dengan kelas tertentu yang menerapkan metode antarmuka. Karena ketika kami
NinjectDependencyResolver
aplikasi, kami mendaftarkan DR sebagai objek dari kelas
NinjectDependencyResolver
, dan di dalam kelas kami menentukan pengikatan antarmuka repositori ke kelas tertentu, ketika meminta kerangka kerja MVC untuk membuat
UsersController
pengontrol
UsersController
, Ninject ketika menganalisis kelas akan menemukan bahwa itu memerlukan implementasi
IUsersRepository
dan
ILanguagesRepository
dan
IUsersRepository
akan membuat instance kelas tertentu dan meneruskannya ke konstruktor kontroler (melalui DR dan kerangka kerja MVC).
Total
Aplikasi sekarang juga mendukung metode akses ke DBMS melalui ORM Entity Framework. Pada saat yang sama, metode akses melalui ADO.NET belum hilang dan dipilih ketika aplikasi diluncurkan oleh parameter, di mana kami menggunakan metode injeksi ketergantungan melalui konstruktor pengontrol menggunakan perpustakaan Ninject.

PS Dan akhirnya: Anda bisa melihat bagaimana proyek ini bekerja di
alamat ini . Dan di
sini Anda dapat mengunduh seluruh proyek. Nah, untuk heap - tautan ke
blog saya .