Như bạn có thể nhớ lại từ Chương 6, bước tiếp theo là tạo ra một cầu nối giữa lớp NinjectDependencyResolver và MVC support cho việc chèn phụ thuộc trong file App_Start/NinjectWebCommon.c
Trang 1CHƯƠNG 7
SportsStore: Một ứng dụng thực tế
Trong chương trước, tôi đã xây dựng các ứng dụng MVC nhanh và đơn giản Tôi đã mô tả mô hình MVC, những tính năng C# thiết yếu và các loại công cụ mà các nhà phát triển MVC yêu cầu Bây giờ là lúc để đưa mọi thứ lại với nhau
và xây dựng một ứng dụng thương mại điện tử đơn giản nhưng thực tế
Ứng dụng của tôi, gọi là SportsStore, sẽ đi theo phương pháp cổ điển được thực hiện bởi các cửa hàng trực tuyến ở mọi nơi Tôi sẽ tạo ra một danh mục sản phẩm trực tuyến mà khách hàng có thể duyệt theo thể loại và theo trang, một giỏ mua hàng, mà người dùng có thể thêm và loại bỏ các sản phẩm, và một checkout, nơi khách hàng có thể nhập các chi tiết giao hàng của họ Tôi cũng sẽ tạo ra một vùng administration bao gồm việc tạo - Create, đọc - Read, cập nhật - Update, và xóa - Delete (CRUD) thuận tiện cho việc quản lý các danh mục; và tôi sẽ bảo mật nó để chỉ có các
administrator đã đăng nhập rồi mới có thể chỉnh sửa
Mục tiêu của tôi trong chương này và những chương sau là để cung cấp cho bạn một cảm giác mà những gì sự phát triển MVC Framework thực sự đem lại bằng việc tạo ra một ví dụ càng thực tế càng tốt Tôi muốn tập trung vào các MVC Framework, tất nhiên, và vì vậy tôi đã đơn giản hóa việc tích hợp với các hệ thống bên ngoài,
chẳng hạn như cơ sở dữ liệu, và bỏ qua hoàn toàn những thứ khác, chẳng hạn như việc xử lý thanh toán
Bạn có thể thấy tôi đi chậm một chút khi tôi xây dựng lên các cấp của cơ sở hạ tầng mà tôi cần Chắc chắn, bạn sẽ
có được những chức năng ban đầu được xây dựng một cách nhanh chóng hơn với Web Forms, chỉ bằng cách kéo và thả các control ràng buộc trực tiếp đến một database
UNIT TESTING (KIỂM TRA ĐƠN VỊ)
Tôi đã tạo nên một vấn đề lớn về sự dễ dàng của unit testing trong MVC, và niềm tin của tôi rằng unit testing là một phần quan trọng của quá trình phát triển Bạn sẽ thấy điều này được chứng minh trong suốt phần này của cuốn sách vì tôi đã bao hàm các chi tiết của unit test và các kỹ thuật có liên quan đến các tính năng MVC quan trọng Tôi biết đây không phải là một ý kiến phổ quát Nếu bạn không muốn unit test, thì cũng không sao Đến cuối cùng, khi tôi phải nói một cái gì đó hoàn toàn về testing, tôi đặt nó trong một sidebar như thế này Nếu bạn không quan tâm đến unit test, bạn có thể bỏ qua ngay các phần này, và ứng dụng SportsStore sẽ chỉ hoạt động hơi ổn Bạn không cần phải làm bất cứ loại unit test nào để có được những tiện ích công nghệ của ASP.NET MVC, mặc dù tất nhiên, hỗ trợ testing là một lý do chính cho việc áp dụng MVC Framework
Hầu hết các tính năng MVC tôi sử dụng cho ứng dụng SportsStore có những chương riêng sau này của nó trong cuốn sách Thay vì lặp lại mọi thứ ở đây, tôi chỉ nói với các bạn một chút để tạo cảm nhận cho ứng dụng ví dụ này và chỉ bạn đến chương khác cho kiến thức chuyên sâu
Tôi sẽ nêu từng bước cần thiết để xây dựng ứng dụng, do đó bạn có thể thấy làm thế nào các tính năng MVC khớp với nhau Bạn nên đặc biệt chú ý khi tôi tạo các view Bạn sẽ nhận được một số kết quả khác nếu bạn không làm theo
Trang 2Tôi sẽ tạo ra một solution Visual Studio có chứa ba project Một project sẽ chứa domain model, một cái sẽ là ứng dụng MVC, và cái thứ ba sẽ chứa các unit test Để bắt đầu, tôi tạo ra một solution Visual Studio mới được gọi là SportsStore sử dụng template Blank Solution, mà bạn có thể tìm thấy trong phần Other Project Types/Visual Studio Solutions Bên trái của hộp thoại New Project, minh họa như Hình 7-1.Nhấn nút
OK để tạo solution
Hình 7-1 Tạo một solution Visual Studio mới
Một solution Visual Studio là một phần chứa một hoặc nhiều project Tôi yêu cầu ba project cho ứng dụng ví dụ của tôi, mà tôi đã mô tả trong Bảng 7-1 Bạn thêm một project bằng cách click phải vào mục Solution trong Solution Explorer và chọn Add New Project từ menu pop-up
Bảng 7-1 Ba Project SportsStore
Trang 3Tên Project Visual Studio Project Template Mục đích
SportsStore.Domain Class Library Giữ các đối tượng domain và logic; thiết lập sự bền
vững thông qua một kho lưu trữ được tạo với Entity Framework
SportsStore.WebUI ASP.NET MVC Web Application (chọn Empty khi
được nhắc để chọn project template và đánh dấu check vào mục MVC)
Giử các controller và view; hoạt động như UI cho ứng dụng SportsStore
SportsStore.UnitTests Unit Test Project Giữ các unit test cho 2 project kia
Tôi luôn luôn chọn Empty cho template ASP.NET MVC Web Application Các lựa chọn khác sẽ thêm một thiết lập ban đầu cho project bao gồm: các thư viện JavaScript, kiểu CSS, và các lớp C # đề cấu hình các tính năng của ứng dụng như là bảo mật và routing Không có cái nào trong đây là xấu - một số thư viện mã nguồn mở mà
Microsoft đã đem ra gần đây trong các project mới là tuyệt vời-nhưng bạn có thể tự thiết lập tất cả các nội dung và cấu hình, và trong khi làm như vậy,ta tìm hiểu thêm về hoạt động của các MVC Framework
Khi bạn đã tạo được ba project, Solution Explorer sẽ giống như Hình 7-2 Tôi đã xóa file Class1.cs mà Visual Studio thêm vào project SportsStore.Domain Vì tôi sẽ không sử dụng nó
Trang 4Hình 7-2 Ba projects được thể hiện trong cửa sổ Solution Explorer
Để debug dễ dàng hơn, chuột phải vào project SportsStore.WebUI và chọn Set as Startup
Project từ menu pop-up (bạn sẽ thấy cái tên chuyển sang in đậm) Điều này nghĩa là khi bạn chọn Start Debugging hoặc Start without Debugging từ menu Debug , thì project này sẽ khởi động
Visual Studio sẽ cố điều hướng đến các file view cá nhân nếu bạn đang chỉnh sửa chúng khi bạn khởi động
debugger, vì vậy click phải vào SportsStore.WebUI project trong Solution Explorer và chọn
Properties từ menu pop-up Click vào Web đề mở các thuộc tính liên quan đến web và chọn Specific Page Không cần nhập giá trị vào trong phần Specific Page Chỉ chọn lựa chọn này là đủ đề ngăn Visual Studio cố gắng đoán URL mà bạn muốn xem và đảm bảo rằng trình duyệt yêu cầu URL gốc cho ứng dụng khi bạn khởi động debugger
Cài dặt các gói công cụ (Tool Packages)
Tôi sẽ sử dụng Ninject và Moq trong chương này Chọn Tools Library Package Manager
Package Manager Console trong Visual Studio đề mở dòng lệnh NuGet và nhập lệnh sau:
Install-Package Ninject -version 3.0.1.10 -projectname
Có nhiều lệnh NuGet để nhập vì tôi được lựa chọn gói nào được cài đặt vào trong project nào, và như trong
những chương trước, tôi chỉ rõ phiên bản của các gói để tải xuống và cài đặt
Thêm References giữa các Project
Tôi cần thiết lập sự phụ thuộc giữa các project và một số các thành phần Microsoft Click phải vào mỗi project trong của sổ Solution Explorer, chọn Add Reference, và thêm các reference được thể hiện trong Bảng 7-2 từ
Trang 5Assemblies Framework, Assemblies Extensions hoặc Solution
Bảng 7-2 Sự phụ thuộc Project được yêu cầu
Tên Project Solution phụ thuộc Assemblies References
SportsStore.Domain None
System.ComponentModel.DataAnnotat ions
System.Web Microsoft.CSharp
Thận trọng Hãy dành thời gian để thiết lập các mối quan hệ một cách chính xác Nếu bạn không có các thư viện và
project references đúng, bạn sẽ gặp vấn đề khi cố gắng build project
Thiết lập DI Container
Trong Chương 6, tôi đã cho bạn thấy làm thế nào sử dụng Ninject để tạo một sự phân giải phụ thuộc tùy chỉnh mà MVC Framework sẽ sử dụng để khởi tạo đối tượng thông qua ứng dụng Tôi sẽ lặp lại tiến trình đó, bắt đầu với việc thêm một thư mục Infrastructure trong SportsStore.WebUI project và thêm một file class gọi là NinjectDependencyResolver.cs trong đó Bạn có thể thấy nội dụng của file mới trong Listing 7-1
Listing 7-1 Nội dung của file NinjectDependencyResolver.cs
public class NinjectDependencyResolver :
IDependencyResolver { private IKernel kernel;
public IEnumerable<object> GetServices(Type
serviceType) { return kernel.GetAll(serviceType);
}
private void AddBindings()
{ // put bindings here }
}
}
Trang 6Như bạn có thể nhớ lại từ Chương 6, bước tiếp theo là tạo ra một cầu nối giữa lớp NinjectDependencyResolver và MVC support cho việc chèn phụ thuộc trong file App_Start/NinjectWebCommon.cs, mà một trong các gói NuGet Ninject đã thêm vào project, như trong
Nếu bạn chọn Start Debugging từ menu Debug, bạn sẽ thấy một trang bị lỗi như Hình 7-3 Điều này là
bởi vì bạn đã request một URL có liên quan với một controller không tồn tại
Trang 7Hình 7-3 Trang bị lỗi
Khởi động Domain Model
Tất cả các project MVC Framework bắt đầu với domain model bởi vì tất cả mọi thứ trong một ứng dụng MVC
Framework đều xoay quanh nó Vì đây là một ứng dụng thương mại điện tử, các thực thể domain rõ ràng nhất mà tôi cần là một sản phẩm Tạo một thư mục mới có tên gọi Entities bên trong project SportsStore.Domain
và sau đó tạo một lớp C # mới tên là Product.cs ở bên trong nó Bạn có thể nhìn cấu trúc này trong Hình 7-4
Trang 8Hình 7-4 tạo lớp Product
Bạn đã quen thuộc với các định nghĩa trong lớp Product, vì vậy tôi sẽ sử dụng một trong những cái mà bạn
đã thấy trong các chương trước Chỉnh sửa lớp Product.cs để nó giống như Listing 7-3
Listing 7-3 Nội dung của lớp Product.cs
namespace SportsStore.Domain.Entities {
public class Product {
public int ProductID { get; set;
} public string Name { get; set;
}
public string Description { get; set;
} public decimal Price { get; set; }
public string Category { get; set; }
}
}
Tôi đang làm theo các kỹ thuật định nghĩa domain model của tôi trong một project Visual Studio riêng biệt, có nghĩa
là các lớp phải được đánh dấu là public Bạn không cần phải tuân theo quy tắc này, nhưng tôi thấy rằng nó giúp giữ cho các model riêng biệt với các controller, điều đó là hữu ích trong các project lớn và phức tạp
Tạo một Abstract Repository
Tôi cần một số cách để nhận các thực thể Product từ một database Như tôi đã giải thích trong Chương 3, model bao gồm việc luận lý học liên tục cho việc lưu trữ và truy xuất dữ liệu từ các kho dữ liệu liên tục, ngay cả bên trong model Tôi muốn giữ một mức độ tách biệt giữa các thực thể data model và nơi lưu trữ và truy xuất lôgic , mà tôi đạt
được bằng cách sử dụng repository pattern Tôi sẽ không lo lắng về việc làm thế nào mà tôi sẽ thực thi dữ liệu liên
tục trong chốc lát, nhưng tôi sẽ bắt đầu quá trình xác định một interface cho nó
Tạo một thư mục cấp cao mới bên trong project SportsStore.Domain tên là Abstract và bên trong thư mục mới, tạo một file interface mới tên là IProductsRepository.cs, nội dung của nó thể hiện ở
Listing 7-4 Nội dung của file IProductRepository.cs
Inerface này sử dụng IEnumerable<T> cho phép người gọi nhận được một trình tự của các đối tượng
Product, mà không cho biết làm thế nào và nơi nào mà dữ liệu được lưu hay truy xuất Một lớp mà phụ thuộc vào interface IProductRepository có thể có được các đối tượng Product mà không cần phải biết gì về nơi nó đến hoặc làm thế nào mà các lớp thực thi sẽ chuyển nó đi Đây là bản chất của repository pattern Tôi sẽ xem lại
interface IProductRepository trong suốt quá trình phát triển để thêm vào các tính năng
Trang 9Tạo ra một Mock Repository
Bây giờ tôi đã định nghĩa một abstract interface, tôi có thể thực hiện các cơ chế liên tục và móc nối nó đến một cơ sở
dữ liệu, nhưng tôi muốn thêm một số thành phần khác của ứng dụng trước Để làm điều này, tôi sẽ tạo ra một mock implementation của interface IProductRepository mà sẽ đứng bên trong đó cho đến khi tôi quay lại chủ đề
về lưu trữ dữ liệu
Tôi định nghĩa mock implementation và ràng buộc nó vào interface IProductRepository trong phương thức AddBindings của lớp NinjectDependencyResolver trong project SportsStore.WebUI, như minh họa trong Listing 7-5
Listing 7-5 Thêm Mock IProductRepository Implementation trong file NinjectDependencyResolver.cs
public class NinjectDependencyResolver :
IDependencyResolver { private IKernel kernel;
}
public IEnumerable<object> GetServices(Type
serviceType) { return kernel.GetAll(serviceType);
}
private void AddBindings() {
Mock<IProductRepository> mock = new Mock<IProductRepository> ();
mock.Setup(m => m.Products).Returns(new List<Product> { new Product { Name = "Football", Price = 25 },
new Product { Name = "Surf board", Price = 179 }, new Product { Name = "Running shoes", Price
= 95 } });
kernel.Bind<IProductRepository>().ToConstant(mock.Object);
Trang 10đó là lý do tại sao tôi sử dụng phương thức ToConstant để thiết lập phạm vi Ninject, như thế này:
kernel.Bind<IProductRepository>().ToConstant(mock.Object) ;
Thay vì tạo ra một thể hiện mới của các đối tượng thực thi mỗi một lần, Ninject sẽ luôn đáp ứng yêu cầu của
interface IProductRepository với cùng mock object
Hiển thị một Danh sách Sản phẩm
Tôi có thể dành phần còn lại của chương này để xây dựng domain model và repository, và không đụng vào các project
UI nào cả Tôi nghĩ rằng bạn sẽ thấy nhàm chán, vì vậy tôi sẽ chuyển các hướng đi và bắt đầu sử dụng MVC
Framework một cách nghiêm túc Tôi sẽ thêm vào các tính năng model và repository mà tôi cần
Trong phần này, tôi sẽ tạo ra một controller và một phương thức hành động để có thể hiển thị thông tin chi tiết của sản phẩm trong repository Trong thời điểm này, đây chỉ là những dữ liệu trong mock repository, nhưng tôi sẽ sắp xếp
sau Tôi cũng sẽ thiết lập một routing configuration ban đầu để MVC biết cách ánh xạ các request cho ứng dụng với
controller mà tôi tạo
Thêm một Controller
Click phải vào thư mục Controllers trong project SportsStore.WebUI và chọn Add
Controller từ menu sổ ra Chọn MVC 5 Controller – Empty, click nút Add và đặt tên
ProductController Click nút Add và Visual Studio sẽ tạo một lớp mới tên là
ProductController.cs, mà bạn nên sửa lại để giống Listing 7-6
Listing 7-6 Nội dung ban đầu của ProductController.cs
Trang 11}
Ngoài việc xóa bỏ phương thức Index, tôi đã thêm một constructor để khai báo một sự phụ thuộc trên interface IProductRepository, nó sẽ dẫn Ninject chèn sự phụ thuộc cho repository sản phẩm khi nó khởi tạo lớp controller Tôi cũng thêm vào namespaces SportsStore.Domain , vì vậy tôi thể tham chiếu các lớp model
và repository mà không cần phải định danh cho nó Tiếp theo, tôi đã thêm một phương thức hành động, tên là
List, mà sẽ trả lại một view thể hiện danh sách đầy đủ của sản phẩm, như được hiển thị trong Listing 7-7
Listing 7-7 Thêm một phương thức hành động trong ProductController.cs
Thêm Layout, View Start File và View
Bây giờ tôi cần phải thêm view mặc định cho phương thức List Nhấp chuột phải vào phương thức List trong lớp HomeController và chọn Add View từ menu pop-up Đặt View Name là List, đặt Template là Empty, và chọn Product cho Model Class, như thể hiện trong Hình 7-5 Đảm bảo rằng Use A Layout Page được đánh dấu check và nhấn vào nút Add để tạo ra view
Trang 12Hình 7-5 Thêm Views/Product/List.cshtml view
Khi bạn nhấn vào nút Add, Visual Studio sẽ tạo ra file List.cshtml, nhưng nó cũng sẽ tạo ra một file _ViewStart.cshtml và một file Shared/_Layout.cshtml Đây là một tính năng hữu ích, phù hợp với cách tiếp cận của Microsoft để mặc định nội dung, file _Layout.cshtml chứa nội dung mẫu mà tôi không muốn và không cần Chỉnh sửa layout sao cho nó phù hợp với nội dung hiển thị trong Listing 7-8
Listing 7-8 Sửa tập tin _Layout.cshtml
Mặc dù tôi đặt model type của view là lớp Product, tôi thực sự muốn làm việc với một
IEnumerable<Product>, đó là những gì Product controller thu được từ các repository và chuyển sang view Trong Listing 7-9, bạn có thể thấy rằng tôi đã chỉnh sửa @model expression và thêm một số cú pháp HTML và Razor để hiển thị chi tiết của sản phẩm
Listing 7-9 Sửa tập tin List.cshtml
Trang 13Mẹo: Tôi chuyển đổi thuộc tính Price cho một chuỗi bằng cách sử dụng phương thức ToString("c"), điều này trả về các giá trị số như là tiền tệ, phù hợp với thiết lập nền văn hóa đang có trên server của bạn Ví dụ, nếu máy chủ được thiết lập là en-US, thì (1002.3).ToString("c")sẽ trả về giá trị $1,002.30, nhưng nếu máy chủ được đặt là en-GB, thì phương thức đó sẽ trả về giá trị £1,002.30 Bạn có thể thay đổi các thiết lập nền văn hóa cho server của bạn bằng cách thêm một phần ở mục <system.web> trong file Web.config như thế này: <globalization culture="en-GB" uiCulture="en-GB" />
Thiết lập Default Route
Tôi cần phải khai báo cho MVC Framework là nó nên gửi các request đến root URL của ứng dụng
chỉnh sửa các dòng lệnh trong phương thức RegisterRoutes trong file
App_Start/RouteConfig.cs, như thể hiện trong Listing 7-10
Listing 7-10 Thêm Default Route trong file RouteConfig.cs
routes.MapRoute(
name: "Default", url: "{controller}/{action}/{id}",
defaults: new { controller = "Product", action =
Mẹo Chú ý rằng tôi đã thiết lập các giá trị của controller trong Listing 7-10 là Product chứ không phải
ProductController, đó là tên của lớp Đây là một phần của naming scheme ASP.NET MVC, trong đó các
lớp controller luôn luôn kết thúc bằng Controller, nhưng bạn bỏ qua phần tên này khi đề cập đến các class
Trang 14hiển thị một danh sách đơn giản chi tiết cho từng sản phẩm Bạn có thể xem kết quả bằng cách chạy thử ứng dụng, như trong Hình 7-6 Nếu bạn không nhận được kết quả như trong hình, kiểm tra xem bạn đã điều hướng đến default URL chưa và không trỏ đến action khác
Trang 15Hình 7-6 Xem các chức năng của ứng dụng cơ bản
Đây là mô hình điển hình của sự phát triển ASP.NET MVC Framework Đầu tư thời gian ban đầu để thiết lập tất cả mọi thứ cần thiết, và rồi các tính năng cơ bản của ứng dụng khớp nhau một cách nhanh chóng
DEBUGGING DỄ HƠN
Khi bạn chạy project từ menu Debug, Visual Studio sẽ tạo ra một cửa sổ trình duyệt mới để hiển thị
ứng dụng, điều này có thể mất vài giây Có một số thủ thuật mà bạn có thể dùng để tăng tốc quá trình
Nếu bạn đang chỉnh sửa tập tin view mà không phải các class, thì bạn có thể thực hiện chỉnh sửa trong Visual Studio trong khi debugger vẫn đang chạy Tải lại cửa sổ trình duyệt khi bạn muốn thấy hiệu ứng của việc chỉnh sửa của bạn ASP.NET sẽ biên dịch lại các view của bạn bên trong các lớp và hiển thị các thay đổi ngay lập tức Visual Studio sẽ không cho bạn chỉnh sửa các file class khi debugger đang chạy hoặc tạo một số thay đổi với project trong Solution Explorer, vì vậy kĩ thuật này hữu dụng nhất khi bạn đang tinh chỉnh sự phù hợp và sự hoàn thiện của HTML mà ứng dụng của bạn tạo ra
Visual Studio 2013 bao gồm một tính năng mới được gọi là browser link , cho phép bạn mở nhiều cửa sổ trình
duyệt và tải lại nó từ thanh menu Visual Studio Tôi giới thiệu tính năng này trong Chương 14
Như một thay thế cuối cùng, bạn có thể giữ cho ứng dụng của bạn mở trong một cửa sổ trình duyệt độc lập Để làm được điều này (giả sử bạn đã khởi chạy debugger ít nhất một lần rồi), kích chuột phải vào biểu tượng IIS Express trong khay hệ thống và chọn URL cho ứng dụng của bạn từ menu pop-up Sau khi bạn đã thực hiện các thay đổi, biên dịch solution trong Visual Studio bằng cách nhấn F6 hoặc chọn Build Build
Solution, và sau đó chuyển sang cửa sổ trình duyệt của bạn và tải lại trang web
Chuẩn bị một Cơ sở dữ liệu
Tôi đã có thể hiển thị các view đơn giản có chứa thông tin chi tiết của sản phẩm, nhưng tôi đang hiển thị dữ liệu test
mà mock IproductRepository trả về Trước khi tôi có thể thực thi một repository thực sự, tôi cần phải thiết lập một cơ sở dữ liệu và đưa vào đó một số dữ liệu
Trang 16Tôi sẽ sử dụng SQL Server như cơ sở dữ liệu, và tôi sẽ truy cập vào cơ sở dữ liệu bằng cách sử dụng Entity Framework (EF), đó là framework Microsoft.NET ORM Một framework ORM thể hiện các bảng, cột, và các hàng của một cơ sở dữ liệu quan hệ thông qua các đối tượng C # bình thường Tôi đã đề cập trong Chương 6 là LINQ có thể làm việc với các nguồn dữ liệu khác nhau, và một trong số này là các Entity Framework Bạn sẽ thấy cách này làm đơn giản hóa mọi thứ trong một thời gian ngắn
Chú ý Đây là vùng mà bạn có thể chọn từ một loạt các công cụ và công nghệ Không chỉ có các cơ sở dữ liệu quan
hệ khác nhau có sẵn, mà bạn cũng có thể làm việc với đối tượng repository, các nơi lưu trữ tài liệu, và một số sự thay thế bí mật Có những framework NET ORM khác cũng khá tốt, mỗi cái trong số đó có một cách tiếp cận hơi khác
nhau: Các biến có thể cung cấp cho bạn một sự phù hợp tốt hơn cho các project của bạn
Tôi đang sử dụng Entity Framework vì một số lý do: nó đơn giản và dễ dàng để gọi nó lên để làm việc; sự tích hợp với LINQ là sự đánh giá đầu tiên ( tôi thích sử dụng LINQ) và nó rất tốt Các bản phân phối trước đó có một chút hit-and-miss (lúc được lúc không), nhưng phiên bản hiện tại thì sang trọng và nhiều tính năng
Tạo Cơ sở dữ liệu
Một tính năng rất hay của Visual Studio và SQL Server là tính năng LocalDB, nó là một sự thực thi administration-free
của các tính năng SQL Server thiết yếu được thiết kế đặc biệt cho các nhà phát triển Sử dụng tính năng này, tôi có thể
bỏ qua quá trình thiết lập một cơ sở dữ liệu khi tôi xây dựng project của tôi và sau đó triển khai một thể hiện SQL Server đầy đủ Hầu hết ứng dụng MVC được triển khai để chứa các môi trường được chạy bởi các quản trị viên chuyên nghiệp Do đó, tính năng LocalDB có nghĩa là việc cấu hình cơ sở dữ liệu có thể trong tầm tay của các DBA và các developer, đạt được với việc lập trình Các tính năng LocalDB được cài tự động với Visual Studio Express 2013 for Web, nhưng bạn có thể tải về trực tiếp từ www.microsoft.com/sqlserver nếu bạn thích
Bước đầu tiên là tạo kết nối cơ sở dữ liệu trong Visual Studio Mở cửa sổ Server Explorer từ menu
View và click nút Connect to Database (nó trông giống như một ổ cắm điện với một dấu cộng
màu xanh)
Bạn sẽ thấy hộp thoại Choose Data Source Chọn Microsoft SQL Server, như trong Hình 7-7,
và click nútContinue (Visual Studio ghi nhớ lựa chọn của bạn, vì vậy bạn sẽ không thấy cửa sổ này nếu bạn đã từng tạo một kết nối trong project khác)
Hình 7-7 Chọn Nguồn Cơ sở dữ liệu
Tiếp theo, bạn sẽ thấy hộp thoại Add Connection Đặt server name là (localdb)\v11.0 Đây là một tên đặc biệt để chỉ ra rằng bạn muốn sử dụng tính năng LocalDB Đánh dấu vào lựa chọn Use Windows
Authentication và đặt tên cơ sở dữ liệu là SportsStore, như trong Hình 7-8
Trang 17Hình 7-8 Thiết lập cơ sở dữ liệu SportsStore
Mẹo Nếu bạn không thấy hộp thoại Choose Data Source, bạn có thể click nút Change ở phía trên bên
phải của hộp thoại Add Connection
Click nút OK và Visual Studio sẽ nhắc bạn tạo cơ sở dữ liệu mới: click Yes để đi tiếp Một mục sẽ xuất hiện trong phần Data Connections của cửa sổ Server Explorer, mà bạn có thể sổ ra để nhìn các khía cạnh khác nhau của
cơ sở dữ liệu, như thể hiện trong Hình 7-9 Bạn sẽ thấy một cái gì đó tương tự, nhưng tên của kết nối cơ sở dữ liệu sẽ khác nhau vì nó bao gồm tên máy tính nội bộ (tên máy của tôi là tiny)
Trang 18Hình 7-9 Cơ sở dữ liệu LocalDB được thể hiện trong cửa sổ Server Explorer
Định nghĩa Sơ đồ Cơ sở dữ liệu (Database Schema)
Như tôi đã giải thích ở đầu chương, sự tập trung của tôi với ứng dụng SportsStore là tập trung vào quá trình phát triển MVC Framework, có nghĩa là giữ cho các thành phần khác mà ứng dụng dựa vào càng đơn giản càng tốt Tôi không muốn quan tâm vào chủ đề thiết kế cơ sở dữ liệu và các chi tiết chuyên sâu về Entity Framework, vượt ra ngoài những
gì tôi cần phải chứng tỏ làm thế nào để dữ liệu vào và ra khỏi một ứng dụng Đây là những chủ đề riêng của nó và nó không phải là một phần của ASP.NET hoặc MVC Framework
Với điều này trong suy nghĩ, tôi sẽ sử dụng một cơ sở dữ liệu mà chỉ chứa một bảng Đây không phải là cách các trang web thương mại điện tử thực sự cấu trúc dữ liệu của họ, tất nhiên, nhưng những bài học quan trọng trong phần này là về các mô hình repository và làm thế nào tôi sử dụng nó để lưu trữ và truy xuất dữ liệu, không phải là cấu trúc của cơ sở dữ liệu
Để tạo bảng cơ sở dữ liệu, click phải vào mục Tables cho cơ sở dữ liệu SportsStore mới trong cửa sổ Server Explorer và chọn Add New Table, như thể hiện trong Hình 7-10
Hình 7-10 Thêm một bảng mới
Trang 19Visual Studio sẽ hiển thị một cửa sổ thiết kế cho việc tạo một bảng mới Bạn có thể tạo một bảng cơ sở dữ liệu mới bằng cách sử dụng giao diện của phần thiết kế, nhưng tôi sẽ sử dụng phần T-SQL bởi vì cách này ngắn gọn và chính xác hơn cho việc mô tả các đặc điểm của bảng mà tôi muốn Nhập câu lệnh SQL được hiển thị trong Listing 7-11 và nhấp vào nút Update ở góc trên bên trái của cửa sổ thiết kế bảng
Listing 7-11 Câu lệnh SQL để tạo bảng trong cơ sở dữ liệu SportsStore
CREATE TABLE Products
(
[ProductID] INT NOT NULL PRIMARY KEY
IDENTITY, [Name] NVARCHAR(100) NOT NULL,
[Description] NVARCHAR(500) NOT
NULL, [Category] NVARCHAR(50) NOT
NULL, [Price] DECIMAL(16, 2) NOT
NULL
)
Câu lệnh này tạo một bảng tên là Products, nó có những cột với các thuộc tính khác nhau mà tôi đã định nghĩa trong lớp Product trước đó trong chương này
Mẹo Đặt thuộc tính IDENTITY cho cột ProductID có nghĩa là SQL Server sẽ tạo ra một giá trị khóa chính
duy nhất khi tôi thêm dữ liệu vào bảng Khi sử dụng một cơ sở dữ liệu trong một ứng dụng Web, có thể khó khăn để tạo ra khóa chính duy nhất vì các request từ người dùng đến một cách đồng thời Với việc dùng tính năng này, tôi có thể lưu trữ các dòng mới và dựa vào SQL Server để sắp ra giá trị duy nhất
Khi bạn click nút Update, Visual Studio sẽ thể hiện tóm tắt kết quả của câu lệnh, như thể hiện trong Hình 7-11
Hình 7-11 Tóm tắt kết quả của câu lệnh SQL
Click nút Update Database để thực thi SQL và tạo bảng Products trong cơ sở dữ liệu Bạn sẽ có thể thấy kết quả của việc cập nhật nếu bạn nhấp vào nút Refresh trong cửa sổ Server Explorer Phần Tables thể hiện bảng Product mới và các chi tiết của mỗi dòng
Mẹo Sau khi bạn đã cập nhật cơ sở dữ liệu, bạn có thể đóng cửa sổ dbo.Products Visual Studio sẽ cho bạn
cơ hội để lưu các tập lệnh SQL được sử dụng để tạo ra cơ sở dữ liệu Bạn không cần phải lưu các tập lệnh trong chương
này, nhưng nó sẽ hữu ích trong các project thực tế nếu bạn cần phải cấu hình nhiều cơ sở dữ liệu
Trang 20Thêm Dữ liệu cho Cơ sở dữ liệu
Tôi sẽ thêm dữ liệu vào cơ sở dữ liệu để có một cái gì đó để làm việc cho đến khi tôi thêm các tính năng quản trị danh mục trong Chương 11
Trong cửa sổ Server Explorer, mở rộng mục Tables của cơ sở dữ liệu SportsStore, kích chuột phải vào bảng Products, và chọn Show Table Data Nhập các dữ liệu được hiển thị trong Hình 7-12 Bạn
có thể di chuyển đến hàng khác bằng cách sử dụng phím Tab Ở cuối mỗi hàng, nhấn tab sẽ di chuyển đến dòng kế tiếp và cập nhật dữ liệu trong cơ sở dữ liệu
Hình 7-12 Thêm dữ liệu vào bảng Products
Chú ý Bạn phải rời khỏi cột ProductID trống Nó là một cột định danh, do đó SQL Server sẽ tạo ra một giá trị duy
nhất khi bạn tab đến hàng tiếp theo
Tôi đã liệt kê các chi tiết sản phẩm trong Bảng 7-3 trong trường hợp bạn không thể tạo ra từ số liệu Nó cũng không quan trọng nếu bạn không nhập các chi tiết đúng như tôi đã làm, mặc dù bạn sẽ thấy kết quả khác nhau từ những cái mà tôi thể hiện khi bạn làm việc thông qua quá trình tạo ra các phần còn lại của ứng dụng SportsStore
Bảng 7-3 Dữ liệu cho bảng Products
Trang 21Tạo Entity Framework Context
Các phiên bản gần đây của Entity Framework có một tính năng khá hay là code-first Ý tưởng là tôi có thể định nghĩa
các lớp trong model của tôi và sau đó tạo ra một cơ sở dữ liệu từ những lớp đó
Điều này là tốt cho các project phát triển green-field, nhưng những cái này rất ít Thay vào đó, tôi sẽ cho bạn thấy một biến thể của code-first, nơi tôi kết hợp các lớp model với một cơ sở dữ liệu hiện có Chọn Tools
Library Package Manager Package Manager Console trong Visual Studio để mở
dòng lệnh NuGet và nhập vào lệnh sau đây:
Install-Package EntityFramework -projectname SportsStore.Domain
Install-Package EntityFramework -projectname SportsStore.WebUI
Mẹo Bạn có thể thấy các lỗi trong Package Manager Console khai báo với bạn rằng binding redirects
(ràng buộc chuyển hướng) không thể được tạo ra Bạn có thể yên tâm bỏ qua những cảnh báo này
Lệnh này thêm các gói Entity Framework cho solution Tôi cần phải cài đặt các gói phần mềm tương tự trong project Domain và WebUI, vì vậy mà tôi tạo ra các lớp mà nó sẽ truy cập vào cơ sở dữ liệu trong project Domain và WebUI
Bước tiếp theo là tạo ra một lớp context mà sẽ kết hợp model với cơ sở dữ liệu Tạo một thư mục mới trong project
SportsStore.Domain gọi là Concrete và thêm một class mới gọi là EFDbContext.cs trong thư mục đó Chỉnh sửa nội dung của file class cho phù hợp với Listing 7-12
Listing 7-12. Nội dung của EFDbContext.cs
using SportsStore.Domain.Entities;
using System.Data.Entity;
namespace SportsStore.Domain.Concrete {
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
}
Để tận dụng lợi thế của các tính năng code-first, tôi cần phải tạo ra một lớp có xuất phát từ
System.Data.Entity.DbContext Lớp này sau đó sẽ tự động xác định một thuộc tính cho mỗi bảng trong cơ sở dữ liệu mà tôi muốn làm việc
Trang 22Tên của thuộc tính sẽ quy định bảng, và tham số kiểu của kết quả DbSet quy định các kiểu model mà Entity
Framework sẽ sử dụng để đại diện cho các hàng trong bảng đó Trong trường hợp này, tên thuộc tính là Products và các tham số kiểu là Product, nghĩa là Entity Framework sẽ sử dụng kiểu model Product để đại diện cho các hàng trong bảng Products
Tiếp theo, tôi cần nói Entity Framework kết nối với cơ sở dữ liệu như thế nào, bằng cách thêm vào một chuỗi kết nối
cơ sở dữ liệu vào file Web.config trong project SportsStore.WebUI với tên giống như các lớp context, như thể hiện trong Listing 7-13
Listing 7-13 Thêm một kết nối cơ sở dữ liệu trong tập tin Web.config
<add key="webpages:Version" value="3.0.0.0"
/> <add key="webpages:Enabled" value="false"
/>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true"
Mẹo Thông báo rằng tôi đã chuyển project ở đây Tôi định nghĩa model và repository logic trong project
SportsStore.Domain, mặc dù thông tin kết nối cơ sở dữ liệu được đặt trong file Web.config trong project SportsStore.WebUI
Cảnh báo Tôi đã phải chia giá trị thuộc tính connectionString trên nhiều dòng để phù hợp với trang này,
nhưng điều quan trọng là phải đặt tất cả mọi thứ trên một dòng trong file Web.config
Sẽ có thẻ add khác trong phần connectionsStrings của file Web.config Visual Studio tạo ra thẻ này theo mặc định và bạn có thể bỏ qua nó hoặc như tôi làm, xóa nó từ tập tin Web.config
Tạo Product Repository
Tất cả những gì còn lại là thêm một lớp vào thư mục Concrete của project
SportsStore.Domain gọi là EFProductRepository.cs Chỉnh sửa lớp của bạn để nó
giống với Listing 7-14
Listing 7-14 Nội dung của EFProductRepostory.cs