ASP.NET MVC - bekerja dengan MySQL melalui ADO.NET

Teknologi Warisan
Peringatan: baik ASP.NET MVC sudah usang dan ADO.NET juga. Dianjurkan untuk menggunakan ASP.NET Core dengan ORM modern. Tetapi jika Anda tertarik, maka bacalah.

Sudah, mungkin, tiga kali saya sampai di ASP.NET MVC. Setelah sepuluh tahun dengan ASP.NET WebForms, agak sulit untuk beralih ke teknologi MVC, karena ada begitu banyak perbedaan sehingga agak lebih mudah untuk membuat daftar apa kesamaan teknologi ini - kecuali perpustakaan .NET Framework. Saya tidak akan menulis di sini - MVC lebih baik atau lebih buruk daripada WebForms, mereka berdua bagus, dan Anda dapat membangun aplikasi yang baik pada kedua teknologi. Saya juga meninggalkan pikiran saya tentang perlunya TDD dengan saya, meskipun saya memilikinya.

Dan sekarang saya akan berbicara tentang tugas yang paling standar - pekerjaan biasa dengan data: melihat daftar catatan dalam bentuk tabel, menambah, mengubah dan menghapus data (operasi CRUD). Namun, di hampir semua buku dan banyak solusi Internet untuk ASP.NET MVC, untuk beberapa alasan, opsi ini secara eksklusif dipertimbangkan melalui ORM (Object Relation Mapping): Entity Framework (EF) atau LINQ untuk SQL. Teknologi sangat baik, tidak diragukan lagi, akhirnya, programmer mungkin tidak mengerti - tetapi bagaimana DBMS yang sangat relasional ini (yang kemungkinan besar ia gunakan) umumnya bekerja, dan bahkan SQL, secara teori, tidak lagi diperlukan: meletakkan dalam bentuk EF dan konektor untuk DBMS akan saling memahami. "Ini dia kebahagiaan - tidak ada lagi keindahan untuk itu." Tetapi bagi para programmer yang tidak takut bekerja secara langsung dengan database melalui mekanisme ADO.NET, seringkali tidak dapat dipahami - dan di mana untuk memulai dengan ASP.NET MVC secara umum dan apakah perlu.

Plus, bagi saya, misalnya, pada awalnya menyebabkan kerusakan liar pada kurangnya komponen yang nyaman untuk menampilkan data dalam tabel kisi. Dapat dipahami bahwa pengembang sendiri harus mengimplementasikan semua ini atau mengambil sesuatu yang cocok dari manajer paket. Jika Anda, seperti saya, sangat senang dengan komponen GridView di ASP.NET WebForms, maka untuk MVC sulit untuk menemukan sesuatu yang lebih atau kurang sebanding, kecuali untuk Grid.mvc. Tetapi kepercayaan saya pada komponen seperti itu tidak cukup untuk menggunakannya untuk proyek yang cukup besar. Jika mereka digunakan, programmer mulai bergantung pada pengembang lain yang, pertama, tidak tahu bagaimana menulis komponen ini (apakah kualitatif?), Dan kedua, tidak diketahui kapan dan bagaimana akan diselesaikan. Tampaknya kadang-kadang bahkan mungkin untuk memperluas komponen dan melihat lebih jauh, tetapi, jika pengembang menyelesaikannya, kami terpaksa menggali kembali kode kami lagi atau membekukan pembaruan komponen pada versi tertentu. Dan jika pengembang memperbaiki kerentanan, Anda masih harus memutakhirkan ke versi yang baru. Bahkan transisi ke versi baru dari konektor MySQL menyebabkan masalah tertentu, meskipun masih dikembangkan oleh perusahaan besar, tetapi bagaimana dengan banyak "sepeda" di manajer paket Nuget?

Jadi, mari kita coba belajar menulis di bawah ASP.NET MVC, sambil bekerja dengan data yang diproses oleh DBMS MySQL. Semua kode dapat diambil di sini di alamat ini , di bawah kode ini akan disajikan sebagian dengan tautan kecil dan penjelasan. Dan di sini Anda dapat melihat aplikasinya.

Buat database di MySQL


CREATE SCHEMA `example`; USE `example`; CREATE TABLE `users` ( `UserID` int(4) unsigned NOT NULL AUTO_INCREMENT, `SupporterTier` enum('None','Silver','Gold','Platinum') NOT NULL DEFAULT 'None', `Loginname` varchar(255) NOT NULL, `LanguageID` int(4) unsigned NOT NULL DEFAULT '2', `Email` varchar(255) DEFAULT NULL, `LastLoginDate` datetime DEFAULT NULL, PRIMARY KEY (`UserID`), KEY `i_Loginname` (`Loginname`), KEY `i_Language_idx` (`LanguageID`), CONSTRAINT `i_Language` FOREIGN KEY (`LanguageID`) REFERENCES `languages` (`LanguageID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; CREATE TABLE `languages` ( `LanguageID` int(4) unsigned NOT NULL AUTO_INCREMENT, `LanguageName` varchar(50) NOT NULL DEFAULT '', `Culture` varchar(10) DEFAULT NULL, PRIMARY KEY (`LanguageID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 

Basis data (DB) akan sederhana dan diwakili oleh hanya dua tabel, dengan satu hubungan satu-ke-banyak di antara mereka di bidang LanguageID . Dengan cara ini saya akan memperumit situasi untuk kebutuhan untuk menggunakan daftar drop-down dari salah satu bahasa untuk pengguna. Selain itu, untuk komplikasi, untuk pengguna, kami juga akan memperkenalkan bidang SupporterTier , yang akan menentukan tingkat dukungan pengguna melalui enum. Dan untuk menggunakan hampir semua tipe data dalam proyek kami, kami menambahkan bidang LastLoginDate dari tipe "tanggal / waktu", yang akan diisi oleh aplikasi itu sendiri ketika pengguna masuk (tidak tercermin dalam proyek ini).

Buat proyek




Pilih "MVC". Dimungkinkan untuk menggunakan "Kosong", tetapi kami memiliki pelatihan, bukan aplikasi nyata, jadi ini akan membantu kami segera, tanpa gerakan yang tidak perlu, mengintegrasikan Bootstrap dan JQuery ke dalam aplikasi kami.



Kami sudah mengisi file Content , Fonts , Scripts folder, serta BundleConfig.cs dan FilterConfig.cs di direktori App_Start dengan bundel dan filter pendaftaran ASP.NET MVC. Dalam proyek kosong, hanya ada pendaftaran rute di file RouteConfig.cs . Di Global.asax.cs, panggilan metode yang dijelaskan dalam file ini juga akan ditambahkan:

 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); 

Kami menyiapkan infrastruktur dan seluruh bundel


Untuk bekerja dengan DBMS MySQL, tambahkan perpustakaan MySql.Data : baik secara manual, jika konektor mysql-connector-net-8.0.18 sudah diinstal pada komputer, atau dari manajer paket Nuget:



Tambahkan konfigurasi string koneksi ke DBMS MySQL ke file Web.config :

 <connectionStrings> <add name="example" providerName="MySql.Data.MySqlClient" connectionString="server=localhost;Port=3306;user id=develop;Password=develop;persistsecurityinfo=True;database=example;CharSet=utf8;SslMode=none" /> </connectionStrings> 

Tambahkan baris ke bagian <appSettings> dengan tautan ke string koneksi yang ditambahkan: <add key="ConnectionString" value="example" />
Kami menambahkan direktori Domain baru ke aplikasi, di dalamnya kami membuat kelas Base statis baru (dalam file Base.cs ), di mana kami mengakses parameter ini:

 public static class Base { private static string ConnectionString { get { return System.Configuration.ConfigurationManager.AppSettings["ConnectionString"]; } } public static string strConnect { get { return System.Configuration.ConfigurationManager.ConnectionStrings[ConnectionString].ConnectionString; } } } 

Saya suka memiliki kelas dasar tertentu dalam aplikasi dengan tautan ke parameter aplikasi dan beberapa fungsi standar yang dapat dipanggil dari seluruh aplikasi.
Nama string koneksi didefinisikan dalam pengaturan aplikasi, sehingga di masa depan akan lebih mudah untuk bekerja dengan string koneksi ke DBMS: dengan cepat beralih antara database yang berbeda dan ubah pengaturan koneksi. Selain itu, mudah untuk menggunakan nama string koneksi dalam parameter aplikasi untuk menerbitkan aplikasi ke Microsoft Azure - di sana Anda dapat mengatur parameter untuk layanan aplikasi yang digunakan untuk penerbitan, dan di dalamnya menentukan string koneksi yang diinginkan, yang ditentukan sebelumnya dalam <connectionStrings> . Kemudian, saat menerbitkan, Anda tidak dapat menggunakan transformasi file web.config .

Saya juga suka menggunakan nilai-nilai dari file sumber daya global dalam teks, agar tidak menimpa mereka di beberapa tempat, jika Anda tiba-tiba membutuhkannya. Sebagai contoh:



Dalam file tata letak halaman _Layout.cshtml (secara standar terletak di direktori Views \ Shared dan akan digunakan nanti untuk semua halaman proyek ini), Anda sekarang dapat menggunakan variabel-variabel ini (lihat, misalnya, Example_Users.Properties.Resources.Title ):

 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title – @Example_Users.Properties.Resources.Title</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <body> <div class="container body-content"> <h1 class="page-header"><a href="/">@Example_Users.Properties.Resources.Title</a></h1> @RenderBody() <hr /> <footer> <p> @DateTime.Now.Year – @Example_Users.Properties.Resources.Author</p> </footer> </div> @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) </body> </html> 

Juga dalam file ini kita melihat lampiran dari style cascading style dari Bootstrap yang terhubung dan pustaka skrip JQuery. Isi dari semua tampilan akan dihasilkan di lokasi panggilan ke fungsi RenderBody() .

M berarti model


Tambahkan file UserClass.cs ke direktori Domain :

 [DisplayName("User")] public class UserClass { [Key] [HiddenInput(DisplayValue=false)] public int UserID { get; set; } [Required(ErrorMessage="Please enter a login name")] [Display(Name = "Login")] public string Loginname { get; set; } public virtual LanguageClass Language { get; set; } [EmailAddress(ErrorMessage = "Please enter a valid email")] public string Email { get; set; } [UIHint("Enum")] [EnumDataType(typeof(Supporter))] [Required(ErrorMessage = "Please select supporter tier")] [Display(Name = "Supporter")] public Supporter SupporterTier { get; set; } [HiddenInput(DisplayValue = true)] [ScaffoldColumn(false)] [Display(Name = "Last login")] public DateTime? LastLoginDate { get; set; } [HiddenInput(DisplayValue = false)] public bool IsLastLogin { get { return LastLoginDate != null && LastLoginDate > DateTime.MinValue; } } public UserClass() {} public UserClass(int UserID, string Loginname, LanguageClass Language, string Email, DateTime? LastLoginDate, Supporter SupporterTier) { this.UserID = UserID; this.Loginname = Loginname; this.Language = Language; this.Email = Email; this.LastLoginDate = LastLoginDate; this.SupporterTier = SupporterTier; } } public enum Supporter { [Display(Name="")] None = 1, Silver = 2, Gold = 3, Platinum = 4 } 

Dan juga file LanguageClass.cs di direktori yang sama:
 [DisplayName("Language")] public class LanguageClass { [Key] [HiddenInput(DisplayValue = false)] [Required(ErrorMessage = "Please select a language")] [Range(1, int.MaxValue, ErrorMessage = "Please select a language")] public int LanguageID { get; set; } [Display(Name = "Language")] public string LanguageName { get; set; } public LanguageClass() {} public LanguageClass(int LanguageID, string LanguageName) { this.LanguageID = LanguageID; this.LanguageName = LanguageName; } } 

Di sini Anda dapat melihat bahwa properti dari kelas mengulangi struktur tabel Users and Languages di DBMS. enum Supporter dibuat untuk tipe enumerasi sehingga dapat digunakan untuk properti kelas SupporterTier bidang serupa di tabel database. Untuk bidang UserID , LanguageID , Anda bisa melihat bahwa itu ditentukan sebagai kunci utama, seperti dalam database. Atribut [Key] digunakan untuk ini.

Semua atribut lainnya lebih cenderung terkait dengan tampilan menggunakan kelas ini. Dan jika kita akan menggunakan helper untuk membentuk tag HTML untuk properti ini (yang secara pribadi saya sarankan), maka kita harus mengatur atribut ini dengan sangat hati-hati untuk mendapatkan yang kita butuhkan. Secara khusus, inilah yang diperlukan untuk proyek ini:

  • [DisplayName] - Digunakan sebagai nama tampilan untuk kelas. Kadang-kadang bisa bermanfaat, dalam proyek ini saya secara khusus menambahkan penggunaan helper Html.DisplayNameForModel untuk demonstrasi.
  • [Display] dengan properti Name - digunakan sebagai nama properti kelas yang ditampilkan di layar. Ada juga properti Order berguna yang memungkinkan Anda untuk memesan urutan menampilkan properti kelas dalam formulir menggunakan pembantu (secara default, mengurutkan berdasarkan urutan di mana properti kelas didefinisikan, sehingga properti Order tidak digunakan dalam proyek ini).
  • [HiddenInput] dengan properti DisplayValue . Ini digunakan untuk properti yang tidak perlu ditampilkan dalam bentuk dan daftar sama sekali ( DisplayValue=false , digambar sebagai tag input bertipe hidden ), atau untuk properti yang masih perlu ditampilkan, tetapi dalam bentuk teks yang tidak dapat diubah ( DisplayValue=true , digambar seperti teks bersih, tanpa tag)
  • [ScaffoldColumn] - menunjukkan apakah akan menampilkan bidang dalam mengedit Html.EditorForModel (misalnya, Html.EditorForModel ). Jika false , maka deskripsi properti kelas atau nilainya tidak akan ditampilkan dalam formulir. [HiddenInput(DisplayValue = false)] tidak dapat digunakan di [HiddenInput(DisplayValue = false)] , karena dalam hal ini nilai-nilai properti kelas ini tidak akan ditampilkan sama sekali tidak hanya dalam formulir input informasi, tetapi juga dalam tampilan tabel. Dalam hal ini, ini diperlukan untuk properti LastLoginDate , yang tidak dimasukkan secara manual, tetapi diisi di suatu tempat secara otomatis, tetapi kita masih perlu melihatnya.
  • [Required] - untuk memeriksa apakah suatu nilai telah dimasukkan untuk properti kelas, dengan teks pesan kesalahan di properti ErrorMessage dan properti AllowEmptyStrings memungkinkan Anda untuk memasukkan baris kosong.
  • [EmailAddress] - pada dasarnya atribut yang sama untuk memeriksa kebenaran alamat surat.

Kelas-kelas model database siap, kita beralih ke representasi (kelas-kelas model untuk representasi akan dijelaskan di bawah).

V - berarti kinerja pembalasan dendam


Di direktori Views , buat direktori Users untuk tampilan kami. Semua tampilan kami menggunakan standar (didefinisikan dalam file _ViewStart.cshtml di direktori Views ) _Layout.cshtml layout yang terletak di direktori Views \ Shared . Buat tampilan Index (file Index.cshtml di direktori Users ):



Dan tulis kodenya:

 @model Example_Users.Models.UsersGrid @{ ViewBag.Title = "Users page"; } @using (@Html.BeginForm()) { <div> <h3>Users list:</h3> @if (TempData["message"] != null) {<div class="text-success">@TempData["message"]</div>} @if (TempData["error"] != null) {<div class="text-warning"><span class="alert">ERROR:</span> @TempData["error"]</div>} @Html.Partial("List") <p> <input type="submit" name="onNewUser" value="New user" /> @*@Html.ActionLink("New user", "New", "Users")*@ </p> </div> } 

Jika kami ingin tampilan ini dimulai secara default, maka buat perubahan ke Default di file RouteConfig.cs :

 routes.MapRoute(name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Users", action = "Index", id = UrlParameter.Optional }); 

Dalam tampilan itu sendiri, Anda perlu memperhatikan baris dengan Html.Partial("List") . Ini diperlukan untuk menggambar di tempat ini tampilan parsial umum terpisah khusus yang terletak di file List.cshtml di direktori Views \ Shared . Sebenarnya, ini adalah tabel kisi untuk menampilkan data dari tabel basis data users kami:

 @model Example_Users.Models.UsersGrid @using Example_Users.Domain <div class="table-responsive"> <table class="table table-bordered table-hover"> <thead> <tr> <th>@Html.ActionLink(Html.DisplayNameFor(m => Model.Users.First().Loginname).ToString(), "Index", Request.QueryString.ToRouteValueDictionary("sortOrder", Model.SortingInfo.NewOrder(Html.NameFor(m => Model.Users.First().Loginname).ToString()))) @Html.SortIdentifier(Model.SortingInfo.currentSort, Html.NameFor(m => Model.Users.First().Loginname).ToString()) </th> <th>@Html.ActionLink(Html.DisplayNameFor(m => Model.Users.First().Language.LanguageName).ToString(), "Index", Request.QueryString.ToRouteValueDictionary("sortOrder", Model.SortingInfo.NewOrder(Html.NameFor(m => Model.Users.First().Language).ToString()))) @Html.SortIdentifier(Model.SortingInfo.currentSort, Html.NameFor(m => Model.Users.First().Language).ToString()) </th> <th>@Html.ActionLink(Html.DisplayNameFor(m => Model.Users.First().Email).ToString(), "Index", Request.QueryString.ToRouteValueDictionary("sortOrder", Model.SortingInfo.NewOrder(Html.NameFor(m => Model.Users.First().Email).ToString()))) @Html.SortIdentifier(Model.SortingInfo.currentSort, Html.NameFor(m => Model.Users.First().Email).ToString()) </th> <th>@Html.ActionLink(Html.DisplayNameFor(m => Model.Users.First().SupporterTier).ToString(), "Index", Request.QueryString.ToRouteValueDictionary("sortOrder", Model.SortingInfo.NewOrder(Html.NameFor(m => Model.Users.First().SupporterTier).ToString()))) @Html.SortIdentifier(Model.SortingInfo.currentSort, Html.NameFor(m => Model.Users.First().SupporterTier).ToString()) </th> <th>@Html.ActionLink(Html.DisplayNameFor(m => Model.Users.First().LastLoginDate).ToString(), "Index", Request.QueryString.ToRouteValueDictionary("sortOrder", Model.SortingInfo.NewOrder(Html.NameFor(m => Model.Users.First().LastLoginDate).ToString()))) @Html.SortIdentifier(Model.SortingInfo.currentSort, Html.NameFor(m => Model.Users.First().LastLoginDate).ToString()) </th> </tr> </thead> <tbody> @foreach (var item in Model.Users) { <tr> <td>@Html.ActionLink(item.Loginname, "Edit", "Users", new { UserID = item.UserID }, null)</td> <td>@Html.DisplayFor(modelitem => item.Language.LanguageName)</td> <td>@Html.DisplayFor(modelitem => item.Email)</td> <td class="@Html.DisplayFor(modelitem => item.SupporterTier)">@if (item.SupporterTier != Supporter.None) {@Html.DisplayFor(modelitem => item.SupporterTier);}</td> <td>@if (item.IsLastLogin) {@Html.DisplayFor(modelitem => item.LastLoginDate)}</td> </tr> } </tbody> </table> </div> @if (Model.PagingInfo.totalPages > 1) { <ul class="pagination"> @Html.PageLinks(Model.PagingInfo, x => Url.Action("Index", new { page = x, sortOrder = Model.SortingInfo.currentSort })) </ul> } 

Dapat dilihat bahwa di header tabel data, Html.DisplayNameFor helper Html.DisplayNameFor untuk menampilkan nama-nama kolom dan untuk ini Anda harus menentukan referensi ke properti objek kelas. Karena ketika membentuk judul tabel kita hanya memiliki objek Model.Users , yang merupakan daftar objek bertipe UserClass , kita harus menggunakan metode berikut: pilih baris pertama daftar ini sebagai objek dari kelas UserClass . Misalnya, untuk nama pengguna: Model.Users.First().Loginname . Karena atribut Loginname dari kelas Users memiliki atribut [Display(Name = "Login")] , itu akan ditampilkan "Login" di nama kolom:



Apa lagi yang menarik dalam tampilan List ? Blok foreach , tentu saja, membuat objek dari kelas UserClass yang ada di daftar Users diterima dari controller. Dan objek SortingInfo dan PagingInfo dalam model UsersGrid kami menarik di sini. Dan kita membutuhkan objek-objek ini untuk mengatur penyortiran data (digunakan pada header tabel pada tag <th> ) dan mengatur pagination informasi (digunakan di bagian bawah halaman, di bawah tabel). Itu sebabnya kami tidak menggunakan sebagai model daftar objek murni dari tipe IEnumerable<UserClass> . Dan sebagai model, kami menggunakan kelas UsersGrid , yang terletak di file UsersGrid.cs di direktori Model .

 public class UsersGrid { public IEnumerable<UserClass> Users { get; set; } public PagingInfo PagingInfo { get; set; } public SortingInfo SortingInfo { get; set; } } 

Dan PagingInfo dan SortingInfo sendiri dalam file GridInfo.cs di tempat yang sama.

 public class PagingInfo { //     public int totalItems { get; set; } //     public int itemsPerPage { get; set; } //   public int currentPage { get; set; } //         public int showPages { get; set; } //   public int totalPages { get { return (int)Math.Ceiling((decimal)totalItems / itemsPerPage); } } //           public int pagesSide { get { return (int)Math.Truncate((decimal)showPages / 2); } } } public class SortingInfo { //  ,     public string currentOrder { get; set; } //   public SortDirection currentDirection { get; set; } //      public string currentSort { get { return currentDirection != SortDirection.Descending ? currentOrder : currentOrder + "_desc"; } } //       (      -   ) public string NewOrder(string columnName) { return columnName == currentOrder && currentDirection != SortDirection.Descending ? columnName + "_desc" : columnName; } } 

Dan untuk digunakan dalam tampilan, pembantu khusus telah ditambahkan ke file GridHelpers.cs (direktori HtmlHelpers ):

 public static class GridHelpers { //     1 ... 3 4 5 ... Last public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl) { StringBuilder result = new StringBuilder(); if (pagingInfo.currentPage > pagingInfo.pagesSide + 1) {//   TagBuilder li = new TagBuilder("li"); li.AddCssClass("page-item"); TagBuilder tag = new TagBuilder("a"); tag.MergeAttribute("href", pageUrl(1)); tag.InnerHtml = "1"; li.InnerHtml = tag.ToString(); result.Append(li.ToString()); } int page1 = pagingInfo.currentPage - pagingInfo.pagesSide; int page2 = pagingInfo.currentPage + pagingInfo.pagesSide; if (page1 < 1) { page2 = page2 - page1 + 1; page1 = 1; } if (page2 > pagingInfo.totalPages) page2 = pagingInfo.totalPages; if (page1 > 2) {// ... TagBuilder li = new TagBuilder("li"); li.AddCssClass("page-item"); TagBuilder tag = new TagBuilder("span"); tag.InnerHtml = "..."; tag.AddCssClass("page-item"); tag.AddCssClass("disabled"); li.InnerHtml = tag.ToString(); result.Append(li.ToString()); } for (int i = page1; i <= page2; i++) {//  TagBuilder li = new TagBuilder("li"); li.AddCssClass("page-item"); if (i == pagingInfo.currentPage) li.AddCssClass("active"); TagBuilder tag = new TagBuilder("a"); tag.AddCssClass("page-link"); tag.MergeAttribute("href", pageUrl(i)); tag.InnerHtml = i.ToString(); li.InnerHtml = tag.ToString(); result.Append(li.ToString()); } if (page2 < pagingInfo.totalPages) {// ...    TagBuilder li = new TagBuilder("li"); li.AddCssClass("page-item"); TagBuilder tag = new TagBuilder("span"); tag.InnerHtml = "..."; tag.AddCssClass("page-item"); tag.AddCssClass("disabled"); li.InnerHtml = tag.ToString(); result.Append(li.ToString()); li = new TagBuilder("li"); li.AddCssClass("page-item"); tag = new TagBuilder("a"); tag.MergeAttribute("href", pageUrl(pagingInfo.totalPages)); tag.InnerHtml = pagingInfo.totalPages.ToString(); li.InnerHtml = tag.ToString(); result.Append(li.ToString()); } return MvcHtmlString.Create(result.ToString()); } public static IHtmlString SortIdentifier(this HtmlHelper htmlHelper, string sortOrder, string field) { if (string.IsNullOrEmpty(sortOrder) || (sortOrder.Trim() != field && sortOrder.Replace("_desc", "").Trim() != field)) return null; string glyph = "glyphicon glyphicon-chevron-up"; if (sortOrder.ToLower().Contains("desc")) { glyph = "glyphicon glyphicon-chevron-down"; } var span = new TagBuilder("span"); span.Attributes["class"] = glyph; return MvcHtmlString.Create(span.ToString()); } public static RouteValueDictionary ToRouteValueDictionary(this NameValueCollection collection, string newKey, string newValue) { var routeValueDictionary = new RouteValueDictionary(); foreach (var key in collection.AllKeys) { if (key == null) continue; if (routeValueDictionary.ContainsKey(key)) routeValueDictionary.Remove(key); routeValueDictionary.Add(key, collection[key]); } if (string.IsNullOrEmpty(newValue)) { routeValueDictionary.Remove(newKey); } else { if (routeValueDictionary.ContainsKey(newKey)) routeValueDictionary.Remove(newKey); routeValueDictionary.Add(newKey, newValue); } return routeValueDictionary; } } 

Karena kisi dengan data tanpa mengurutkan dan tanpa informasi paging adalah hal yang agak tidak berguna, dan tidak ada penolong standar untuk seluruh tabel data di ASP.NET MVC, Anda harus membuatnya sendiri (atau mengambil yang dibuat oleh orang lain). Dalam hal ini, saya melihat beberapa implementasi dalam buku ASP.NET MVC dan solusi yang disajikan di Internet. Selain itu, untuk beberapa alasan, solusi yang menggabungkan setidaknya penyortiran data dan pagination, baik tidak sama sekali, atau saya tidak menemukan. Saya harus memahami semua ini, menggabungkan dan memodifikasinya ke keadaan normal. Sebagai contoh, pagination dalam implementasi tersebut sering tidak memberikan output dari daftar halaman yang kurang lebih panjang - yah, bagaimana jika akan ada beberapa ribu halaman? Saya memberikan contoh tampilan untuk solusi yang disajikan di atas:



Kami juga membutuhkan tampilan untuk membuat dan memodifikasi data. Lihat untuk membuat objek tipe UserClass :



Dan kode tampilan akan terlihat seperti ini:

 @model Example_Users.Models.UserModel @{ ViewBag.Title = "New " + Html.DisplayNameForModel().ToString().ToLower(); } <h2>@ViewBag.Title</h2> @using (@Html.BeginForm("New", "Users", FormMethod.Post)) { @Html.EditorFor(m => m.User); @Html.LabelFor(m => Model.User.Language)<br /> @Html.DropDownListFor(m => Model.User.Language.LanguageID, Model.SelectLanguages()) <span/>@Html.ValidationMessageFor(m => Model.User.Language.LanguageID)<br /> <br /> <p><input type="submit" name="action" value="Add" /> <input type="button" onclick="history.go(-1)" value="Cancel" /></p> @*<p>@Html.ActionLink("Back to list", "Index")</p>*@ } 

Pandangan ini menunjukkan, misalnya, penggunaan helper Html.EditorFor sebagai sarana untuk menghasilkan tag untuk mengedit semua properti objek di kelas UserClass . Ini ditampilkan sebagai berikut:



Tampilan ini menggunakan kelas UserModel sebagai model, bukan UserClass secara langsung. Kelas UserModel sendiri terletak di file UserModel.cs di direktori Models :

 public class UserModel { public UserClass User { get; set; } private IList<LanguageClass> Languages { get; set; } public UserModel() {} public UserModel(UserClass user, IList<LanguageClass> languages) { this.User = user; this.Languages = languages; } public IEnumerable<SelectListItem> SelectLanguages() { if (Languages != null) { return new SelectList(Languages, "LanguageID", "LanguageName"); } return null; } } 

Objek UserClass itu sendiri dan daftar tambahan objek tipe LanguageClass termasuk dalam kelas ini. Kami membutuhkan daftar ini untuk membuat daftar drop-down bahasa, dengan bahasa pengguna saat ini dipilih di dalamnya: @Html.DropDownListFor(m => Model.User.Language.LanguageID, Model.SelectLanguages(), "")

Helper ini menggunakan panggilan ke fungsi SelectLanguages() , yang mengubah daftar bahasa menjadi objek tipe SelectList dengan parameter pengidentifikasi dan nama baris yang telah ditetapkan. Menempatkan generasi objek ini ke tampilan akan salah, karena idenya adalah tidak mengetahui tentang ikatan ini dengan nama bidang. SelectList saja, akan mungkin untuk menghasilkan SelectList langsung di controller, tapi saya suka opsi dengan daftar pribadi objek kelas domain dan fungsi lebih.

Untuk menghasilkan daftar drop-down, kita harus menggunakan bantuan yang terpisah, karena pembantu Html.EditorFor(m => m.User) tidak akan menghasilkan markup pengeditan untuk objek yang disematkan tipe LanguageClass (ini bisa dilewati dengan menulis template umum untuk daftar drop-down, tetapi di sini kita kami tidak akan melakukan ini ...).

Dan karena kami menggunakan objek kelas UserModel dalam pandangan kami, yang mencakup objek lain dari kelas UserClass , kami tidak akan dapat menggunakan helper Html.EditorForModel() , karena helper tidak rekursif dan tidak akan berfungsi dalam situasi ini, oleh karena itu helper Html.EditorFor() digunakan Html.EditorFor() untuk objek User .

: Html.ActionLink("Back to list", "Index")

. , -, , – button , - . -, – – UserClass , . – : /> , . , , (, , , – ), .

UserClass :



:

 @model Example_Users.Models.UserModel @{ ViewBag.Title = "Edit " + Html.DisplayNameForModel().ToString().ToLower(); } <h2>@ViewBag.Title @Model.User.Loginname</h2> @using (@Html.BeginForm("Edit", "Users", FormMethod.Post)) { @Html.HiddenFor(m => Model.User.UserID) <div> @Html.LabelFor(m => Model.User.Loginname) @Html.EditorFor(m => Model.User.Loginname) @Html.ValidationMessageFor(m => Model.User.Loginname) </div> <div> @Html.LabelFor(m => Model.User.Language) @Html.DropDownListFor(m => Model.User.Language.LanguageID, Model.SelectLanguages()) @Html.ValidationMessageFor(m => Model.User.Language.LanguageID) </div> <div> @Html.LabelFor(m => Model.User.Email) @Html.EditorFor(m => Model.User.Email) @Html.ValidationMessageFor(m => Model.User.Email) </div> <div> @Html.LabelFor(m => Model.User.SupporterTier) @Html.EditorFor(m => Model.User.SupporterTier) @*@Html.EnumDropDownListFor(m => Model.User.SupporterTier)*@ @*@Html.DropDownListFor(m => m.Model.User.SupporterTier, new SelectList(Enum.GetNames(typeof(Example_Users.Domain.Supporter))))*@ @Html.ValidationMessageFor(m => Model.User.SupporterTier) </div> <br /> <p><input type="submit" name="action" value="Save" /> <input type="submit" name="action" value="Remove" onclick="javascript:return confirm('Are you sure?');" /> <input type="submit" name="action" value="Cancel" /></p> } 

. – :



. : /> , ( Save , Remove ): /> , ( . ).

Enum


, enum . , Html.EditorFor() , ( <input type=”text”/> ), - (.. <select> <option> ).

1. Html.DropDownListFor() Html.ListBoxFor() , , : @Html.DropDownListFor(m => m.Model.User.SupporterTier, new SelectList(Enum.GetNames(typeof(Example_Users.Domain.Supporter)))) . – Html.EditorForModel() Html.EditorFor() .

2. Editor . Supporter.cshtml Views\Shared\EditorTemplates :

 @model Example_Users.Domain.Supporter @Html.DropDownListFor(m => m, new SelectList(Enum.GetNames(Model.GetType()), Model.ToString())) 

, Html.EditorFor(m => Model.SupporterTier) , Html.EditorFor(m => Model.SupporterTier, "Supporter") . -, [UIHint("Supporter")] . , Html.EditorForModel()Html.EditorFor(m => Model.SupporterTier, "Supporter") .

- , ( New ) Html.EditorFor() Html.EditorForModel() : « , , NULL, «Example_Users.Domain.Supporter», NULL. » – , . .

3. Html.EnumDropDownListFor() , . , , , . «»: Html.EditorForModel() Html.EditorFor() , , Html.EnumDropDownListFor() . , , – [UIHint] , [DataType] [EnumDataType] . , None , , , Supporter.

4. Sebagai hasilnya, saya datang dengan opsi solusi yang ditemukan di Internet : membuat template umum untuk transfer. Buat file Enum.cshtml di folder Views \ Shared \ EditorTemplates :

 @using System.ComponentModel.DataAnnotations @model Enum @{ Func<object, string> GetDisplayName = o => { var result = null as string; var display = o.GetType() .GetMember(o.ToString()).First() .GetCustomAttributes(false) .OfType<DisplayAttribute>() .LastOrDefault(); if (display != null) result = display.GetName(); return result ?? o.ToString(); }; var values = Enum.GetValues(ViewData.ModelMetadata.ModelType).Cast<object>() .Select(v => new SelectListItem { Selected = v.Equals(Model), Text = GetDisplayName(v), // v.ToString(), Value = v.ToString() }); } @Html.DropDownList("", values) 

Di sini, secara umum, semuanya menjadi baik: templat berfungsi dengan baik jika memungkinkan. Anda bahkan [UIHint("Enum")]tidak bisa menambahkan. Selain itu, template umum ini membaca atribut [Display(Name)]untuk nilai enumerasi menggunakan fungsi khusus.

C berarti pengontrol


Tambahkan file UsersController.cs ke direktori Controllers .

 public class UsersController : Controller { public int pageSize = 10; public int showPages = 15; public int count = 0; //    public ViewResult Index(string sortOrder, int page = 1) { string sortName = null; System.Web.Helpers.SortDirection sortDir = System.Web.Helpers.SortDirection.Ascending; sortOrder = Base.parseSortForDB(sortOrder, out sortName, out sortDir); UsersRepository rep = new UsersRepository(); UsersGrid users = new UsersGrid { Users = rep.List(sortName, sortDir, page, pageSize, out count), PagingInfo = new PagingInfo { currentPage = page, itemsPerPage = pageSize, totalItems = count, showPages = showPages }, SortingInfo = new SortingInfo { currentOrder = sortName, currentDirection = sortDir } }; return View(users); } [ReferrerHold] [HttpPost] public ActionResult Index(string onNewUser) { if (onNewUser != null) { TempData["referrer"] = ControllerContext.RouteData.Values["referrer"]; return View("New", new UserModel(new UserClass(), Languages())); } return View(); } [ReferrerHold] public ActionResult New() { TempData["referrer"] = ControllerContext.RouteData.Values["referrer"]; return View("New", new UserModel(new UserClass(), Languages())); } [HttpPost] public ActionResult New(UserModel model) { if (ModelState.IsValid) { if (model.User == null || model.User.Language == null || model.User.Language.LanguageID == 0) RedirectToAction("Index"); UsersRepository rep = new UsersRepository(); if (rep.AddUser(model.User)) TempData["message"] = string.Format("{0} has been added", model.User.Loginname); else TempData["error"] = string.Format("{0} has not been added!", model.User.Loginname); if (TempData["referrer"] != null) return Redirect(TempData["referrer"].ToString()); return RedirectToAction("Index"); } else { model = new UserModel(model.User, Languages()); // -          model.Languages,   return View(model); } } [ReferrerHold] public ActionResult Edit(int UserID) { UsersRepository rep = new UsersRepository(); UserClass user = rep.FetchByID(UserID); if (user == null) return HttpNotFound(); TempData["referrer"] = ControllerContext.RouteData.Values["referrer"]; return View(new UserModel(user, Languages())); } [HttpPost] public ActionResult Edit(UserModel model, string action) { if (action == "Cancel") { if (TempData["referrer"] != null) return Redirect(TempData["referrer"].ToString()); return RedirectToAction("Index"); } if (ModelState.IsValid) { if (model.User == null || model.User.Language == null || model.User.Language.LanguageID == 0) RedirectToAction("Index"); UsersRepository rep = new UsersRepository(); if (action == "Save") { if (rep.ChangeUser(model.User)) TempData["message"] = string.Format("{0} has been saved", model.User.Loginname); else TempData["error"] = string.Format("{0} has not been saved!", model.User.Loginname); } if (action == "Remove") { if (rep.RemoveUser(model.User)) TempData["message"] = string.Format("{0} has been removed", model.User.Loginname); else TempData["error"] = string.Format("{0} has not been removed!", model.User.Loginname); } if (TempData["referrer"] != null) return Redirect(TempData["referrer"].ToString()); return RedirectToAction("Index"); } else { model = new UserModel(model.User, Languages()); return View(model); } } public IList<LanguageClass> Languages() { IList<LanguageClass> languages = new List<LanguageClass>(); LanguagesRepository rep = new LanguagesRepository(); languages = rep.List(); return languages; } } 

:

1) Index

: public ViewResult Index(string sortOrder, int page = 1)

sortOrder page . page - , sortOrder , SQL- . ( , Base.cs ): sortOrder = Base.parseSortForDB(sortOrder, out sortName, out sortDir);

, UsersRepository ( , ), List UsersGrid . totalItem List , UsersGrid . .

Index [HttpPost] , New Index : public ActionResult Index(string onNewUser)

onNewUser /> Index , null . submit Index , ( «New user»).

UserModel , UserClass New . LanguageRepository List :

 public IList<LanguageClass> Languages() { LanguagesRepository rep = new LanguagesRepository(); return rep.List(); } 

2) New

New New User Html.ActionLink("New user", "New", "Users") Index . ( New ) , , .

New model UserModel : public ActionResult New(UserModel model)

New UserModel , ( , UserClass LanguageClass ), UsersRepository , AddUser(model.User) . ( New ) .

3) Edit

Edit UserID ( ) : public ActionResult Edit(int UserID)

UsersRepository FetchByID(UserID) UserClass . – UserModel Edit .

UserModel action : public ActionResult Edit(UserModel model, string action)

UserModel ( ) Edit . , action , HTML- input . value . Cancel , . , New , Edit . ActionFilter : ReferrerHoldAttribute ReferrerHoldAttribute.cs ( HtmlAttribute ):

 public class ReferrerHoldAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var referrer = filterContext.RequestContext.HttpContext.Request.UrlReferrer; if (referrer != null) filterContext.RouteData.Values.Add("referrer", referrer); base.OnActionExecuting(filterContext); } } 

, « New user » : TempData["referrer"] = ControllerContext.RouteData.Values["referrer"];

, . , , .

, , New Edit , , : if (TempData["referrer"] != null) return Redirect(TempData["referrer"].ToString());

action Save Remove , UsersRepository ChangeUser(model.User) RemoveUser(model.User) . ( Edit ) .

ADO.NET MySQL –


- . Users , , , , Languages .

MySQL.Data MySqlCommand :

 using (MySqlConnection connect = new MySqlConnection( )) { string sql = " "; using (MySqlCommand cmd = new MySqlCommand(sql, connect)) { cmd.Parameters.Add(" ",  ).Value =  ; connect.Open(); result = cmd.ExecuteNonQuery() >= 0; //        (INSERT, UPDATE, DELETE)   cmd.ExecuteScalar()         SELECT } } 

MySqlDataReader , :
 using (MySqlConnection connect = new MySqlConnection( )) { string sql = " "; using (MySqlDataReader dr = cmd.ExecuteReader()) { cmd.Parameters.Add(" ",  ).Value =  ; objConnect.Open(); while (dr.Read()) {//       } } } 

UserRepository.cs Models :

 public class UsersRepository { public bool AddUser(UserClass user) { user.UserID = AddUser(Name: user.Loginname, LanguageID: user.Language.LanguageID, Email: user.Email, SupporterTier: user.SupporterTier); return user.UserID > 0; } public int AddUser(string Name, int LanguageID, string Email, Supporter SupporterTier) { int ID = 0; using (MySqlConnection connect = new MySqlConnection(Base.strConnect)) { string sql = "INSERT INTO `Users` (`Loginname`, `LanguageID`, `Email`, `SupporterTier`) VALUES (@Loginname, @LanguageID, @Email, @SupporterTier)"; using (MySqlCommand cmd = new MySqlCommand(sql, connect)) { cmd.Parameters.Add("Loginname", MySqlDbType.String).Value = Name; cmd.Parameters.Add("LanguageID", MySqlDbType.Int32).Value = LanguageID; cmd.Parameters.Add("Email", MySqlDbType.String).Value = Email; cmd.Parameters.Add("SupporterTier", MySqlDbType.Int32).Value = SupporterTier; connect.Open(); if (cmd.ExecuteNonQuery() >= 0) { sql = "SELECT LAST_INSERT_ID() AS ID"; cmd.CommandText = sql; int.TryParse(cmd.ExecuteScalar().ToString(), out ID); } } } return ID; } public bool ChangeUser(UserClass user) { return ChangeUser(ID: user.UserID, Name: user.Loginname, LanguageID: user.Language.LanguageID, Email: user.Email, SupporterTier: user.SupporterTier); } public bool ChangeUser(int ID, string Name, int LanguageID, string Email, Supporter SupporterTier) { bool result = false; if (ID > 0) { using (MySqlConnection connect = new MySqlConnection(Base.strConnect)) { string sql = "UPDATE `Users` SET `Loginname`=@Loginname, `LanguageID`=@LanguageID, `Email`=@Email, `SupporterTier`=@SupporterTier WHERE UserID=@UserID"; using (MySqlCommand cmd = new MySqlCommand(sql, connect)) { cmd.Parameters.Add("UserID", MySqlDbType.Int32).Value = ID; cmd.Parameters.Add("Loginname", MySqlDbType.String).Value = Name; cmd.Parameters.Add("LanguageID", MySqlDbType.Int32).Value = LanguageID; cmd.Parameters.Add("Email", MySqlDbType.String).Value = Email; cmd.Parameters.Add("SupporterTier", MySqlDbType.Int32).Value = SupporterTier; connect.Open(); result = cmd.ExecuteNonQuery() >= 0; } } } return result; } public bool RemoveUser(UserClass user) { return RemoveUser(user.UserID); } public bool RemoveUser(int ID) { using (MySqlConnection connect = new MySqlConnection(Base.strConnect)) { string sql = "DELETE FROM `Users` WHERE `UserID`=@UserID"; using (MySqlCommand cmd = new MySqlCommand(sql, connect)) { cmd.Parameters.Add("UserID", MySqlDbType.Int32).Value = ID; connect.Open(); return cmd.ExecuteNonQuery() >= 0; } } } public UserClass FetchByID(int ID) { UserClass user = null; using (MySqlConnection objConnect = new MySqlConnection(Base.strConnect)) { string strSQL = "SELECT u.`UserID`, u.`Loginname`, l.`LanguageID`, l.`LanguageName`, u.`Email`, u.`LastLoginDate`, CAST(u.`SupporterTier` AS UNSIGNED) as `SupporterTier` FROM `Users` u LEFT JOIN `Languages` l ON l.LanguageID=u.LanguageID WHERE `UserID`=@UserID"; using (MySqlCommand cmd = new MySqlCommand(strSQL, objConnect)) { objConnect.Open(); int UserID = 0, LanguageID = 0; string Loginname = null, LanguageName= null, Email = String.Empty; Supporter SupporterTier = Supporter.None; DateTime? LastLoginDate = null; cmd.Parameters.Add("UserID", MySqlDbType.Int32).Value = ID; using (MySqlDataReader dr = cmd.ExecuteReader()) { if (dr.Read()) { UserID = dr.GetInt32("UserID"); Loginname = dr.GetString("Loginname").ToString(); LanguageID = dr.GetInt32("LanguageID"); LanguageName = dr.GetString("LanguageName").ToString(); if (!dr.IsDBNull(dr.GetOrdinal("Email"))) Email = dr.GetString("Email").ToString(); if (!dr.IsDBNull(dr.GetOrdinal("LastLoginDate"))) LastLoginDate = dr.GetDateTime("LastLoginDate"); if (!dr.IsDBNull(dr.GetOrdinal("SupporterTier"))) SupporterTier = (Supporter)dr.GetInt32("SupporterTier"); } LanguageClass language = null; if (LanguageID > 0) language = new LanguageClass(LanguageID: LanguageID, LanguageName: LanguageName); if (UserID > 0 && language != null && language.LanguageID > 0) user = new UserClass(UserID: UserID, Loginname: Loginname, Language: language, Email: Email, LastLoginDate: LastLoginDate, SupporterTier: (Supporter)SupporterTier); } } } return user; } //       ASP.NET WebForms,             ObjectDataSource      //     ,         " "         //public IEnumerable<DataRow> List() //{ // using (MySqlConnection objConnect = new MySqlConnection(Base.strConnect)) // { // string strSQL = "select * from users"; // using (MySqlCommand objCommand = new MySqlCommand(strSQL, objConnect)) // { // objConnect.Open(); // using (MySqlDataAdapter da = new MySqlDataAdapter(objCommand)) // { // DataTable dt = new DataTable(); // da.Fill(dt); // return dt.AsEnumerable(); // } // } // } //} public IList<UserClass> List(string sortOrder, System.Web.Helpers.SortDirection sortDir, int page, int pagesize, out int count) { List<UserClass> users = new List<UserClass>(); using (MySqlConnection objConnect = new MySqlConnection(Base.strConnect)) { //     string sort = " ORDER BY "; //   ,               (inject) // ,  , MySQL        //    ,         (       ) //        ,    if (sortOrder != null && sortOrder != String.Empty) { sort += "`" + sortOrder + "`"; if (sortDir == System.Web.Helpers.SortDirection.Descending) sort += " DESC"; sort += ","; } sort += "`UserID`"; //   //        ( ) string limit = ""; if (pagesize > 0) { int start = (page - 1) * pagesize; limit = string.Concat(" LIMIT ", start.ToString(), ", ", pagesize.ToString()); } string strSQL = "SELECT SQL_CALC_FOUND_ROWS u.`UserID`, u.`Loginname`, l.`LanguageID`, l.`LanguageName` as `Language`, u.`Email`, u.`LastLoginDate`, CAST(u.`SupporterTier` AS UNSIGNED) as `SupporterTier` FROM `Users` u LEFT JOIN `Languages` l ON l.LanguageID=u.LanguageID" + sort + limit; using (MySqlCommand cmd = new MySqlCommand(strSQL, objConnect)) { objConnect.Open(); cmd.Parameters.Add("page", MySqlDbType.Int32).Value = page; cmd.Parameters.Add("pagesize", MySqlDbType.Int32).Value = pagesize; using (MySqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { LanguageClass language = new LanguageClass(LanguageID: dr.GetInt32("LanguageID"), LanguageName: dr.GetString("Language").ToString()); users.Add(new UserClass( UserID: dr.GetInt32("UserID"), Loginname: dr.GetString("Loginname"), Language: language, Email: dr.IsDBNull(dr.GetOrdinal("Email")) ? String.Empty : dr.GetString("Email"), LastLoginDate: dr.IsDBNull(dr.GetOrdinal("LastLoginDate")) ? (DateTime?) null : dr.GetDateTime("LastLoginDate"), SupporterTier: dr.IsDBNull(dr.GetOrdinal("SupporterTier")) ? (Supporter) Supporter.None : (Supporter)dr.GetInt32("SupporterTier"))); } } } using (MySqlCommand cmdrows = new MySqlCommand("SELECT FOUND_ROWS()", objConnect)) { int.TryParse(cmdrows.ExecuteScalar().ToString(), out count); } } return users; } } 

AddUser , ( ChangeUser ), ( RemoveUser ), ( FetchByID ) List . List :

  1. ( DataTable ), – . Yaitu SQL-. UserClass .
  2. LIMIT SQL- SELECT . , MySQL , LIMIT . , , ORDER BY . , SQL-, SQL , , . , , : .
  3. SQL SELECT FOUND_ROWS() , , SELECT SQL_CALC_FOUND_ROWS LIMIT .

, .

LanguageRepository.cs Models :

 public class LanguagesRepository { public IList<LanguageClass> List() { List<LanguageClass> languages = new List<LanguageClass>(); using (MySqlConnection objConnect = new MySqlConnection(Base.strConnect)) { string strSQL = "SELECT `LanguageID`, `LanguageName` as `Language` FROM `Languages` ORDER BY `LanguageName`"; using (MySqlCommand cmd = new MySqlCommand(strSQL, objConnect)) { objConnect.Open(); using (MySqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { LanguageClass language = new LanguageClass(LanguageID: dr.GetInt32("LanguageID"), LanguageName: dr.GetString("Language").ToString()); languages.Add(language); } } } } return languages; } } 

, LanguageClass .

Total


– . , : , , , .. dll. - - . «» , , ASP.NET MVC ADO.NET , MS SQL.

PS : , . . — .

Source: https://habr.com/ru/post/id482346/


All Articles