TẠO DATA ACCESS LAYER

Trong bài này ta sẽ tạo, truy cập và nhận dữ liệu từ DB sử dụng Entity Framework (EF) Code First. Để hiểu được bài này, bạn cần hoàn thành bài trước đó . Về EF thì tài liệu trên mạng cũng khá nhiều, nếu có thời gian mình sẽ viết một bài tóm lại các kiến thức vừa đủ dùng về nó.

Chúng ta sẽ học:

  • Tạo data model
  • Khởi tạo và thêm dữ liệu vào DB
  • Kết nối ứng dụng vào DB.

Các chức năng ta sẽ tìm hiểu:

  • Entity Framework Code First
  • LocalDB
  • Data Annotations

TẠO DATA MODELS

EF là một ORM Framework (ánh xạ đối tượng – quan hệ) giúp chúng ta hoạt động dễ dàng hơn với DB. Tham khảo thêm ở đây. EF hỗ trợ các mô hình sau:

  • DB First: sử dụng khi có sẵn DB, EF tự động tạo ra data model và class, đây là cách đơn giản nhất.
  • Model First: Ta sẽ tự thiết kế mới một CSDL sao đó EF sẽ tự sinh ra code.
  • Code First: ta sẽ tự tạo ra các class của riêng mình, EF sẽ sinh DB dựa trên những gì ta đã viết. Đây là cách được dùng phổ biến nhất.

Các mô hình trong EF

0-1

Note: Mặc định trong project của ta đã được thêm sẵn EF, ta có thể thấy trong References các file sau:

  • EntityFramework.dll
  • EntityFrameworkSqlServer.dll

Nếu không có, ta thêm thủ công bằng cách nhấn chuột phải vào References -> Manage NuGet Packages…Tìm và cài vào project.

1

Entity Classes

Các class bạn tạo để định nghĩa schema của data gọi là entity class. Để dễ hiểu cứ nghĩ entity class như một table trong database.Mỗi thuộc tính trong class tương ứng với các cột trong 1 bảng ở DB.

Trong Tuts này, bạn sẽ bắt đầu bằng cách thêm một entity class thể hiện schema cho bảng Products và Catagories. Class Products chứa các định nghĩa cho mỗi product, gồm: ProductID, ProductName, Description, ImagePath, UnitPrice, CategoryID và Category. Class Category sẽ chứa các định nghĩa cho mỗi Catagory mà Product thuộc về, ví dụ Car, Boat, or Plane. Các thuộc tính trong Category: CategoryID, CategoryName, Description, and Products. Mỗi Product thuộc về một Category. Class Entity này sẽ được thêm vào folder Model trong project.

  1. Trong Solution Explorer, thêm thư mục Models, sau đó chọn Add -> New Item.

1-2

  1. Ta thêm class có tên Products

1-3

  1. Gõ đoạn code dưới đây vào class mới tạo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System.ComponentModel.DataAnnotations;
namespace DMWingtipToys.Models
{
    public class Product
    {
        [ScaffoldColumn(false)]
 
        public int ProductID { get; set; }
 
 
        [Required, StringLength(100), Display(Name = “Name”)]
 
        public string ProductName { get; set; }
 
 
        [Required, StringLength(10000), Display(Name = “Product Description”), DataType(DataType.MultilineText)]
 
        public string Description { get; set; }
 
 
        public string ImagePath { get; set; }
 
 
        [Display(Name = “Price”)]
 
        public double? UnitPrice { get; set; }
 
 
        public int? CategoryID { get; set; }
 
 
        public virtual Category Category { get; set; }
 
    }
 
}
  1. Thêm class Category.cs tương tự:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Collections.Generic;
 
using System.ComponentModel.DataAnnotations;
 
namespace DMWingtipToys.Models
 
{
 
public class Category
 
{
 
[ScaffoldColumn(false)]
 
public int CategoryID { get; set; }
 
[Required, StringLength(100), Display(Name = “Name”)]
 
public string CategoryName { get; set; }
 
[Display(Name = “Product Description”)]
 
public string Description { get; set; }
 
public virtual ICollection<Product> Products { get; set; }
 
}
 
}

Như chúng ta đã đề cập, class Category chính là loại của Product (ví dụ: Cars, Boats, Rockets…), tức là mỗi sản phẩm thì sẽ thuộc một loại mặt hàng nhất định. Mỗi Product ứng với mỗi hàng trong DB và mỗi thuộc tính của class Product sẽ map đến mỗi cột tương ứng trong bảng

Data Annotaion

Bạ̣n có thể thấy rằng một số thành phần của class có thuộc tính ở trên đầu của nó. Ví dụ [ScaffoldColumn(false)] (ẩn cột). Đó gọi là Data Annotaions (chú thích). Các thuộc tính của Data Annotation giúp kiểm tra dữ liệu, định dạng và xác định cách nó được mô hình hóa khi DB tạo ra.

Context Class

Để sử dụng các lớp truy cập dữ liệu, ta định nghĩa một context class. Context class quản lí các entity class(ví dụ Product, Category) và giúp truy cập vào DB

Tại folder Models, ta thêm lớp ProductContext.cs với nội dung :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Data.Entity;
 
namespace DMWingtipToys.Models
 
{
 
public class ProductContext : DbContext
 
{
 
public ProductContext() : base(“WingtipToys”)
 
{
 
}
 
public DbSet<Category> Categories { get; set; }
 
public DbSet<Product> Products { get; set; }
 
}
 
}

Đoạn code trên có namspace System.Data.Entity, do đó ta có thể truy cập tất cả các phương thức cốt lõi của Entity Framwork: truy vấn, insert, update, delete dữ liệu bằng cách làm việc với các đối tượng strongly typed(Strongly type giúp bạn truy suất trực tiếp đến các thành phần bên trong như bảng, cột thông qua tên của chúng với sự hỗ trợ của InteliSense, tên, kiểu của dữ liệu được xác định rõ, hạn chế lỗi).

Class ProductContext giúp tìm kiếm, lưu trữ và update table Product trong DB. Class ProductContext kế thừa từ DbContext.

Initializer Class

Ta cần cài thêm vài logic để cài đặt DB trong lần đầu tiên chạy. Cho phép dữ liệu mới thêm vào DB có thể lập tức được hiển thị.

Trong folder Models, thêm classProductDatabaseInitializer.cscó nội dung:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
using System.Collections.Generic;
 using System.Data.Entity;
namespace DMWingtipToys.Models
 
{
 
public class ProductDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProductContext>
 
{
 
protected override void Seed(ProductContext context)
 
{
 
GetCategories().ForEach(c => context.Categories.Add(c));
 
GetProducts().ForEach(p => context.Products.Add(p));
 
 
base.Seed(context);
 
}
 
 
private static List<Category> GetCategories()
 
{
 
var categories = new List<Category> {
 
new Category
 
{
 
CategoryID = 1,
 
CategoryName = “Cars”
 
},
 
new Category
 
{
 
CategoryID = 2,
 
CategoryName = “Planes”
 
},
 
new Category
 
{
 
CategoryID = 3,
 
CategoryName = “Trucks”
 
},
 
new Category
 
{
 
CategoryID = 4,
 
CategoryName = “Boats”
 
},
 
new Category
 
{
 
CategoryID = 5,
 
CategoryName = “Rockets”
 
},
 
};
 
 
return categories;
 
}
 
 
private static List<Product> GetProducts()
 
{
 
var products = new List<Product> {
 
new Product
 
{
 
ProductID = 1,
 
ProductName = “Convertible Car”,
 
Description = “This convertible car is fast! The engine is powered by a neutrino based battery (not included).” +
 
“Power it up and let it go!”,
 
ImagePath=“carconvert.png”,
 
UnitPrice = 22.50,
 
CategoryID = 1
 
},
 
new Product
 
{
 
ProductID = 2,
 
ProductName = “Old-time Car”,
 
Description = “There’s nothing old about this toy car, except it’s looks. Compatible with other old toy cars.”,
 
ImagePath=“carearly.png”,
 
UnitPrice = 15.95,
 
CategoryID = 1
 
},
 
new Product
 
{
 
ProductID = 3,
 
ProductName = “Fast Car”,
 
Description = “Yes this car is fast, but it also floats in water.”,
 
ImagePath=“carfast.png”,
 
UnitPrice = 32.99,
 
CategoryID = 1
 
},
 
new Product
 
{
 
ProductID = 4,
 
ProductName = “Super Fast Car”,
 
Description = “Use this super fast car to entertain guests. Lights and doors work!”,
 
ImagePath=“carfaster.png”,
 
UnitPrice = 8.95,
 
CategoryID = 1
 
},
 
new Product
 
{
 
ProductID = 5,
 
ProductName = “Old Style Racer”,
 
Description = “This old style racer can fly (with user assistance). Gravity controls flight duration.” +
 
“No batteries required.”,
 
ImagePath=“carracer.png”,
 
UnitPrice = 34.95,
 
CategoryID = 1
 
},
 
new Product
 
{
 
ProductID = 6,
 
ProductName = “Ace Plane”,
 
Description = “Authentic airplane toy. Features realistic color and details.”,
 
ImagePath=“planeace.png”,
 
UnitPrice = 95.00,
 
CategoryID = 2
 
},
 
new Product
 
{
 
ProductID = 7,
 
ProductName = “Glider”,
 
Description = “This fun glider is made from real balsa wood. Some assembly required.”,
 
ImagePath=“planeglider.png”,
 
UnitPrice = 4.95,
 
CategoryID = 2
 
},
 
new Product
 
{
 
ProductID = 8,
 
ProductName = “Paper Plane”,
 
Description = “This paper plane is like no other paper plane. Some folding required.”,
 
ImagePath=“planepaper.png”,
 
UnitPrice = 2.95,
 
CategoryID = 2
 
},
 
new Product
 
{
 
ProductID = 9,
 
ProductName = “Propeller Plane”,
 
Description = “Rubber band powered plane features two wheels.”,
 
ImagePath=“planeprop.png”,
 
UnitPrice = 32.95,
 
CategoryID = 2
 
},
 
new Product
 
{
 
ProductID = 10,
 
ProductName = “Early Truck”,
 
Description = “This toy truck has a real gas powered engine. Requires regular tune ups.”,
 
ImagePath=“truckearly.png”,
 
UnitPrice = 15.00,
 
CategoryID = 3
 
},
 
new Product
 
{
 
ProductID = 11,
 
ProductName = “Fire Truck”,
 
Description = “You will have endless fun with this one quarter sized fire truck.”,
 
ImagePath=“truckfire.png”,
 
UnitPrice = 26.00,
 
CategoryID = 3
 
},
 
new Product
 
{
 
ProductID = 12,
 
ProductName = “Big Truck”,
 
Description = “This fun toy truck can be used to tow other trucks that are not as big.”,
 
ImagePath=“truckbig.png”,
 
UnitPrice = 29.00,
 
CategoryID = 3
 
},
 
new Product
 
{
 
ProductID = 13,
 
ProductName = “Big Ship”,
 
Description = “Is it a boat or a ship. Let this floating vehicle decide by using its “ +
 
“artifically intelligent computer brain!”,
 
ImagePath=“boatbig.png”,
 
UnitPrice = 95.00,
 
CategoryID = 4
 
},
 
new Product
 
{
 
ProductID = 14,
 
ProductName = “Paper Boat”,
 
Description = “Floating fun for all! This toy boat can be assembled in seconds. Floats for minutes!” +
 
“Some folding required.”,
 
ImagePath=“boatpaper.png”,
 
UnitPrice = 4.95,
 
CategoryID = 4
 
},
 
new Product
 
{
 
ProductID = 15,
 
ProductName = “Sail Boat”,
 
Description = “Put this fun toy sail boat in the water and let it go!”,
 
ImagePath=“boatsail.png”,
 
UnitPrice = 42.95,
 
CategoryID = 4
 
},
 
new Product
 
{
 
ProductID = 16,
 
ProductName = “Rocket”,
 
Description = “This fun rocket will travel up to a height of 200 feet.”,
 
ImagePath=“rocket.png”,
 
UnitPrice = 122.95,
 
CategoryID = 5
 
}
 
};
 
 
return products;
 
}
} 
}

Khi DB tạo ra và khởi tạo hoàn tất, phương thức Seed bị ghi đè và cài đặt. khi Seed được set, các giá trị từ Categories và Product được lưu vào DB. Nếu ta update dữ liệu bằng cách thay đổi các giá trị trên sau khi DB được tạo, ta sẽ không thấy bất cứ thay đổi nào trên Web. Do code trên kế thừa từ lớp “DropCreateDatabaseIfModelChanges” để nhận ra việc thay đổi trên model(schema) trước khi reset data. Nếu không có gì thay đổi ở entity class Category và Product(tên, kiểu của thuộc tính, phương thức…) thì DB sẽ không bị tạo lại.

Lưu ý: Nếu ta muốn DB luôn luôn tạo lại mỗi khi chạy ứng dụng ta dùng class DropCreateDatabaseAlways thay vì DropCreateDatabaseIfModelChanges.

Sau khi hoàn thành các bước trên, ta có hình dưới đây:1-4

Cấu hình ứng dụng để dùng Data Model

Bây giờ ta đã tạo class đại diện cho dữ liệu, ta phải cấu hình ứng dụng để dùng các class đó. Trong file Global.asax, thêm vào code để khởi tạo các model. Trong Web.config thêm thông tin cho ứng dụng biết DB nào dùng để lưu data. File Global.asax có thể dùng để xử lí các sự kiện hay phương thức. File Web.config cho phép cấu hình ứng dụng của ta.

Cập nhật file Global.asax:

Thêm đoạn code được hightlight như trong hình vào phương thức Application_Start trong Global.asax:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  using System;
 
using System.Collections.Generic;
 
using System.Linq;
 
using System.Web;
 
using System.Web.Optimization;
 
using System.Web.Routing;
 
using System.Web.Security;
 
using System.Web.SessionState;
 
using System.Data.Entity;
 
using DMWingtipToys.Models;
 
using DMWingtipToys.Logic;
 
 
namespace DMWingtipToys
 
{
 
    public class Global : HttpApplication
 
    {
 
        void Application_Start(object sender, EventArgs e)
 
        {
 
            // Code that runs on application startup
 
            RouteConfig.RegisterRoutes(RouteTable.Routes);
 
            BundleConfig.RegisterBundles(BundleTable.Bundles);
 
 
            // Initialize the product database.
 
            Database.SetInitializer(new ProductDatabaseInitializer());
 
        }
 
       }
 
}

Khi chạy ứng dụng cài đặt các giá trị vào DB.

Chỉnh sửa file Web.config:

                        Thêm thông tin connection vào ứng dụng cho phép ta chọn nơi lưu DB. Bằng việc thêm mới một  connectionstring, ta có thể trực tiếp lưu DB trong thư mục App_Data, chứ không phải vị trí default của nó.

Chạy thử chương trình

Tổng kết

Trong bài hướng dẫn này ta đã tạo Data model, thêm giá trị vào DB cũng như cấu hình cho ứng dụng truy cập vào DB khi chạy ứng dụng.

 

 
 

ĐỂ LẠI PHẢN HỒI CỦA BẠN TẠI ĐÂY

Phản hồi về bài viết này

NO COMMENTS

LEAVE A REPLY


*