Tự học lập trình cơ sở dữ liệu với Visual Basic 5 trong 21 ngày ấn phẩm 2



tải về 0.58 Mb.
trang9/13
Chuyển đổi dữ liệu26.04.2018
Kích0.58 Mb.
#37160
1   ...   5   6   7   8   9   10   11   12   13

Mã trong đoạn 3.3 là tất cả các cái bạn cần để mở một cơ sở dữ liệu Micsoft Acess đã có và tạo Dynaset- type Recordset sẵn sàng cho cập nhật. Tuy vậy đối với đề án này, bạn muốn xem thêm một đoạn. Chúng ta hãy thêm một vài đoạn mã cho bạn biết bao nhiêu bản ghi trong bảng Titles.


Bạn cần hơn một biến để giữ việc đếm bản ghi. Bạn cũng có thể sử dụng phương thức MoveLast để chuyển con trỏ bản ghi đến bản ghi cuối cùng trong Recordset. Bạn lấy tổng số bằng cách đọc thuộc tính RecordCount của Recordset. Khi bạn có tất cả cái đó, bạn hiện thị một hộp thông báo của Visual Basic nói cho bạn biết có bao nhiêu bản ghi trong Recordset. Xem doạn 3.4.
Đoạn 3.4: Đếm các bản ghi trong một Dynaset.
Private Sub Form_Load()

`

` creating dynaset-type recordsets



`

Dim db As Database ` the database object

Dim rs As Recordset ` the recordset object

`

` create local variables



Dim strDBName As String

Dim strRSName As String

Dim intRecs As Integer

`

` initialize the variables



strDBName = App.Path & "\..\data\books5.mdb"

strRSName = "Titles"

`

` create the objects



Set db = DBEngine.OpenDatabase(strDBName)

Set rs = db.OpenRecordset(strRSName, dbOpenDynaset)

`

` count the records in the collection



rs.MoveLast ` move to end of list to force a count

intRecs = rs.RecordCount ` get count

MsgBox strRSName & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

`

End Sub



Hãy lưu form ( DYNASETS. FRM ) và đề án ( DYNASETS.VBP ) lại và chạy chương trình. Bạn nhìn thấy một hộp thông báo đang cho bạn thấy có bao nhiêu bản ghi trong Recordset. Hình 3.3 cho bạn thấy kết quả.
Hình 3.3 :
Bạn có thể sử dụng lệnh OpenRecordset trên một Recordset đã có để tạo một subset nhỏ hơn của dữ liệu. Cái này thường được làm khi người sử dụng cho phép tạo một bản ghi chọn chuẩn. Nếu dataset là quá lớn, người sử dụng cho phép thêm sự tìm kiếm bằng cách tạo thêm tiêu chuẩn để áp dụng đến dataset.
Chúng ta hãy thay đổi DYNASETS.VBP để tạo một Dynaset-type Recordset nhỏ hơn từ Recordset đã có. Bạn cần tạo một đối tượng Recordset mới và một biến mới gọi là strFilter để nắm giữ tiêu chuẩn cho việc chọn lựa bản ghi. Xem đoạn mã 3.5.
Đoạn 3.5 : Thêm một đối tượng Recordset và biến xâu mới.
Private Sub Form_Load()

`

` creating dynaset-type recordsets



`

Dim db As Database ` the database object

Dim rs As Recordset ` the recordset object

Dim rs2 As Recordset ` <<< add another recordset object

`

` create local variables



Dim strDBName As String

Dim strRSName As String

Dim intRecs As Integer

Dim strFilter As String ` <<< add filter

`

` initialize the variables



strDBName = App.Path & "\..\data\books5.mdb"

strRSName = "Titles"

strFilter = "YearPub>1990" ` <<< set filter

`

` create the objects



Set db = DBEngine.OpenDatabase(strDBName)

Set rs = db.OpenRecordset(strRSName, dbOpenDynaset)

`

` count the records in the collection



rs.MoveLast ` move to end of list to force a count

intRecs = rs.RecordCount ` get count

MsgBox strRSName & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

`

End Sub


Bây giờ bạn có đối tượng và biến ( được đánh dấu <<< trong đoạn 3.5), bạn có thể thêm đoạn mã đó để tạo Recordset mới. Đầu tiên bạn đặt thuộc tính Filter của Recordset đã có bằng cách sử dụng biến bạn vừa tạo. Sau đó bạn tạo một Recordset mới từ một cái cũ. xem hai dòng cuối của đoạn 3.6.

Đoạn 3.6 : Sử dụng thuộc tính Filter để tạo một Recordset.


Private Sub Form_Load()

`

` creating dynaset-type recordsets



`

Dim db As Database ` the database object

Dim rs As Recordset ` the recordset object

Dim rs2 As Recordset ` another recordset

`

` create local variables



Dim strDBName As String

Dim strRSName As String

Dim intRecs As Integer

Dim strFilter As String

`

` initialize the variables



strDBName = App.Path & "\..\data\books5.mdb"

strRSName = "Titles"

strFilter = "YearPub>1990"

`

` create the objects



Set db = DBEngine.OpenDatabase(strDBName)

Set rs = db.OpenRecordset(strRSName, dbOpenDynaset)

`

` count the records in the collection



rs.MoveLast ` move to end of list to force a count

intRecs = rs.RecordCount ` get count

MsgBox strRSName & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

`

` create filtered collection



rs.Filter = strFilter

Set rs2 = rs.OpenRecordset

`

End Sub
Bây giờ bạn đã tạo một Recordset mới, bạn có thể lấy một count of selected các bản ghi. Bạn có thể thêm đoạn mã tương tự bạn sử dụng lúc trước. Chuyển đến cuối của Recordset lấy RecordCount và xem nó trong một hộp thông báo. Đoạn 3.7 được xem như chương trình đầy đủ.


Đoạn 3.7 :
Private Sub Form_Load()

`

` creating dynaset-type recordsets



`

Dim db As Database ` the database object

Dim rs As Recordset ` the recordset object

Dim rs2 As Recordset ` another recordset

Dim rs3 As Recordset ` for cloning

`

` create local variables



Dim strDBName As String

Dim strRSName As String

Dim intRecs As Integer

Dim strFilter As String

`

` initialize the variables



strDBName = App.Path & "\..\..\data\books5.mdb"

strRSName = "Titles"

strFilter = "YearPub>1990"

`

` create the objects



Set db = DBEngine.OpenDatabase(strDBName)

Set rs = db.OpenRecordset(strRSName, dbOpenDynaset)

`

` count the records in the collection



rs.MoveLast ` move to end of list to force a count

intRecs = rs.RecordCount ` get count

MsgBox strRSName & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

`

` create filtered collection



rs.Filter = strFilter

Set rs2 = rs.OpenRecordset

`

` count the records in the collection



rs2.MoveLast ` move to end of list to force a count

intRecs = rs2.RecordCount ` get count

MsgBox strFilter & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

` exit program

End

`

End Sub


Hãy lưu và chạy đoạn mã để kiểm tra kết quả ( xem hình 3.4 ). Chú ý rằng record count đầu tiên lớn hơn record count thứ hai.
Hình 3.4 :
Nó cũng quan trọng để chú ý rằng đối tượng Recodset thứ hai được tạo từ đối tượng Recordset thứ nhất. Nó là một sức mạnh đặc biệt của Visual Basic. Khi bạn muốn lấy một dataset nhỏ hơn, bạn không phải nạp lại dữ liệu từ cơ sở dữ liệu. Bạn có thể sử dụng một Recordset có sẵn như nguồn cho một dataset mới.


Mẹo : Việc tạo các subset mới của một Recordset trong cách này có thể thỉnh thoảng cũng chậm hơn việc đơn giản tạo một Recordset mới từ bản thân cơ sở dữ liệu. Ngoại lệ đối với quy tắc này là khi cơ sở dữ liệu của bạn được lưu tại một server xa. Trong trường hợp dữ liệu nguồn của bạn ở xa và chỉ sẵn dùng quá một mạng kết nối chậm, việc sử dụng thuộc tính Filter để tạo các subset của dữ liệu có thể nhanh hơn.

Bây giờ chúng ta làm một loạt thay đổi đến DYNASET. VBP để làm rõ phương thức Clone cho Recordset. Việc nhái một Recordset để làm một bản sao của set. Thêm vào đối tượng dữ liệu khác ( rs3 ) và thêm clone Recordset trong đoạn 3.8 :


Đoạn 3.8 : Nhái lại một Recordset mới.
Private Sub Form_Load()

`

` creating dynaset-type recordsets



`

Dim db As Database ` the database object

Dim rs As Recordset ` the recordset object

Dim rs2 As Recordset ` another recordset

Dim rs3 As Recordset ` for cloning

`

` create local variables



Dim strDBName As String

Dim strRSName As String

Dim intRecs As Integer

Dim strFilter As String

`

` initialize the variables



strDBName = App.Path & "\..\data\books5.mdb"

strRSName = "Titles"

strFilter = "YearPub>1990"

`

` create the objects



Set db = DBEngine.OpenDatabase(strDBName)

Set rs = db.OpenRecordset(strRSName, dbOpenDynaset)

`

` count the records in the collection



rs.MoveLast ` move to end of list to force a count

intRecs = rs.RecordCount ` get count

MsgBox strRSName & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

`

` create filtered collection



rs.Filter = strFilter

Set rs2 = rs.OpenRecordset

`

` count the records in the collection



rs2.MoveLast ` move to end of list to force a count

intRecs = rs2.RecordCount ` get count

MsgBox strFilter & " :" & CStr(intRecs), vbInformation, "Total Records in Set"

`

` clone the recordset



Set rs3 = rs.Clone ` clone it

rs3.MoveLast ` move to end

intRecs = rs3.RecordCount ` get count

MsgBox "Cloned Recordset: " & CStr(intRecs), vbInformation, "Total Records in Set"

`

End Sub
Chú ý rằng tất cả các cái bạn phải làm để nhái một Recordset là sử dụng phương thức Clone để nạp một đối tượng Recordset mới. Khi bạn chạy chương trình thời điểm này, bạn nhìn thấy Recordset đó được tạo sử dụng phương thức Clone chứa đựng số các bản ghi tương tự như mẹ của nó. Các Dynaset co thể được sử dụng các Boookmark, Filter,và Sort Dynaset-type Recordset có thể sử dụng các thuộc tính Bookmark, Filter,Sort để sắp xếp lại dữ liệu để hiện thị ( Sort) hoặc tạo subset của Recordset ( Filter ). Việc sử dụng phương thức Find của Visual Basic Recordset ảnh hưởng Visual Basic để bắt đầu tại bản ghi đầu tiên trong tập hợp và đọc từng bản ghi cho đến một bản ghi thoả mãn được tìm thấy. Khi mà bản ghi chọn lựa được tìm thấy, người sử dụng của bạn có thể muốn quay trở lại bản ghi đó để hiện thị trước khi cuộc tìm kiếm bắt đầu. Đó là những gì Boookmark của Visual Basic làm. Chúng nhớ bạn ở đâu.


Khi bạn tìm kiếm một bản ghi trong dataset sử dụng một phương thức Find, bạn nên đặt các Bookmark trước khi cuộc tìm kiếm của bạn được nhớ bạn bắt đầu ở đâu. Đây là một cái thuận tiện, nếu kết quả tìm kiếm của bạn trong một bản ghi rỗng. Khi một Phương thức FindFirst lỗi trong việc xác định bản ghi mong muốn, con trỏ bản ghi đặt đến bản ghi đầu tiên trong tập hợp. Nếu bạn có lưu boookmark trước khi bắt đầu tìm kiếm, bạn có thể đặt lại Bookmark của Visual Basic và trả lại người sử dụng nơi cuộc tìm kiếm bắt đầu.
Chúng ta xây dựng nhanh một đề án để chứng minh mục đích của các Bookmark. Sử dụng thông tin trong hình 3.1 để tạo một form nhỏ với một điểu khiển dữ liệu, hai điều khiển bound input, hai điều khiển nhãn ( label ) và một nút lệnh.
Bảng 3.1 : Các điều khiển cho BOOKMARK. FRM.
Hình 3.5 :
Khi bạn đã hoàn thành form layout, thêm đoạn mã sau vào nút lệnh. Đoạn 3.9 là một chốt thông thường để lưu vị trí hiện thời trong bảng bằng cách đọc (và lưu ) Bookmark, hoặc phục hồi vị trí trước trong bảng bằng cách đọc (và cập nhật ) Bookmark.
Đoạn 3.9 :
Private Sub cmdSaveBookmark_Click()

`

` show how bookmarks work



`

Static blnFlag As Boolean

Static strBookmark As String

`

If blnFlag = False Then



`

` flip flag and set caption

blnFlag = True

cmdSaveBookmark.Caption = "&Restore Bookmark"

`

` save bookmark for later



strBookmark = dtaBookMarks.Recordset.Bookmark

MsgBox "Bookmark Saved", vbInformation

Else

`

` flip flag and set caption



blnFlag = False

cmdSaveBookmark.Caption = "&Save Bookmark"

`

` restore saved bookmark



dtaBookMarks.Recordset.Bookmark = strBookmark

End If


`

End Sub



Mẹo : Đoạn 3.9 sử dụng hai biến tĩnh. Các biến tĩnh giữ giá trị của chúng thậm trí sau khi thủ tục kết thúc. Việc sử dụng các biến tĩnh trong chương trình của bạn là một cách hay để giữ các giá trị sau khi thủ tục hoặc hàm exit.Chỉ có cách khác để làm chắc chắn rằng các biến duy trì giá trị của chúng sau khi thoát từ thủ tục đến nơi của chúng trong vùng định nghĩa của form. Vấn đề với vị trí của chúng tại sự khai báo của form-level là bây giờ chúng có thể thay đổi bằng các thủ tục trong các thủ tục và các hàm khác trên form tương tự. Định nghĩa các biến tĩnh bên trong các thủ tục....(thiếu).

Lưu form là BOOKMARKS. FRM và project là BOOKMARKS.VBP và sau đó chạy chương trình. Chương trình mở tệp tin BOOKS5.MDB, nó tạo một Dynaset-type Recordset của tất cả các bản ghi trong bảng Authors và luôn đưa ra bản ghi đầu tiên trên form. Chú ý rằng caption của nút lệnh nói Save Bookmark. Kích vào nút lệnh để tạo một Bookmark trỏ đến bản ghi này của tập hợp. Caption thay đổi thành Restore Bookmark. Bây giờ sử dụng các nút mũi tên trên thanh dữ liệu điều khiển để chuyển đến bản ghi khác trên form. Kích vào nút lệnh. Bạn nhìn thấy rằng con trỏ bản ghi đã trở lại bản ghi đầu tiên trong tập hợp. Đó là bởi vì thuộc tính Recordset Bookmark đã đặt lại giá trị bạn lưu trước đó. Các Dynaset và ODBC nếu bạn đang ttruy cập dữ liệu từ một dữ liệu nguồn ODBC ( Open Database Connectivity ). Chỉ có đối tượng dữ liệu của Visual Basic bạn có thể sử dụng để cập nhật bảng dữ liệu cơ sở là một Dynaset-type Recordset. Bạn học thêm về kết nối cơ sở dữ liệu ODBC vào ngày thứ 19, “ ODBC Data Access Via the ODB C API ”.


Những mặt hạn chế của đối tượng dynaset-type Recordset :
Mặc dù Dynaset là đối tượng tuyệt hảo, nó có một vài hạn chế phải xem xét. Cái chủ yếu trong số đó là các Dynaset không cho phép bạn chỉ rõ một index có sẵn,và bạn không thể sử dụng được phương thức Seek của Visual Basic để nhanh chóng xác định một bản ghi đơn trong Dynaset. Ngoài ra các lỗi có thể xảy ra khi hiện thị các bản ghi trong một Dynaset, nếu các bản ghi trong bảng cơ sở đã bị thay đổi hoặc bị xoá bởi người sử dụng khác. Dynaset Access và Seek Limittations Dynasets không thể được sử dụng các đối tượng Index đã có trong một cơ sở dữ liệu bởi vì Index được xây dựng để điều khiển toàn bộ bảng dữ liệu và không chỉ một subset của dữ liệu. Bởi vì các Dynaset có thể là các subset của bảng dữ liệu, Index là vô ích. Ngoài ra bạn không thể chỉ rõ một đối tượng Index cho một Dynaset, bạn không thể sử dụng phương thức Seek của Visual Basic trên Dynaset.
Đó chỉ là các giới hạn nhỏ. Nếu bạn đã định nghĩa một Index trong bảng cơ sở với cờ Primary được bật. Data engine của Visual Basic sử dụng index của khoá chính khi tạo Dynaset. Nó thường đặt Dynaset trong cách tối ưu nhất. Thậm chí, ngay cả bạn không sử dụng phương thức Seek trên Dynaset, bạn có thể sử dụng các phương thức FindFirst, FindNext, FindPrevious, và FindLast . Chúng đủ nhanh đối với các hoạt động trên các Dyanaset từ nhỏ tới lớn. Bạn học thêm về phương thức Seek, Find và Move vào ngày thứ 10 “ Việc tạo các chương trình cơ sở dữ liệu với mã Visual Basic ”. Dynamic Membership- Related Errors Nếu chương trình của bạn mở một cơ sở dữ liệu và tạo một Dynaset từ một bảng cơ sở trong khi người sử dụng khác cũng mở cơ sở dữ liệu tương tự và một Dynaset cơ bản trên một bảng cơ sở tương tự. Nó có thể thực hiện điều đó khi cả hai người sử dụng sẽ cố gắng thêm những bản ghi tương tự nhau. Nếu cả hai user thêm những bản ghi tương tự nhau và cả hai cố gắng lưu lại các bản ghi đến bảng cơ sở, người thứ hai cố gắng lưu để lưu bản ghi nhậ được một lỗi của Visual Basic.
Khi người thứ hai cố gắng lưu bản ghi, Visual Basic tìm ra xem nguồn gốc của bản ghi trong bảng cơ sở đã được thay đổi. Trong nội quy để bảo vệ cái chuẩn của cơ sở dữ liệu, Visual Basic không cho phép cập nhật bảng.
Khi sử dụng đối tượng dữ liệu Dynaset-type Recordset.
Đối tượng Dynaset nên được sử dụng trong hầu hết các chương trình cơ sở dữ liệu bạn viết. Trong hầu hết các trường hợp, đối tượng Dynaset của Visual Basic phần lớn có hiệu lực đối tượng truy cập của dữ liệu để sử dụng. Nó cung cấp cho bạn một cách để tạo một dyanmic, updatable subset của các bản ghi trong một hoặc nhiều bảng. Đối tượng Dynaset là đối tượng mặc định được tạo bằng bound data control và chỉ đối tượng updatable bạn có thể sử dụng để truy cập các dữ liệu nguồn của ODBC.
Dynaset không là một đối tượng tốt để sử dụng khi bạn cần làm một số lượng lớn của record-oriented xử lý trên các dataset lớn. Như chỉ số tìm kiếm của các tệp tin toàn tác. nếu bạn có một chương trình Visual Basic sử dụng Dynaset và nó trình bày chậm cơ sở dữ liệu thực thi, tìm kiếm các vị trí ở đó bạn có thể giới hạn kích cỡ của các Dynaset bằng cách thu hẹp lựa chọn chuẩn.
Đối tượng Table-type Recordset.
Đối tượng dữ liệu table-type Recordset của Visual Basic là đối tượng cho phép bạn truy cập đến bảng vật lý, thỉnh thoảng được xem như bảng cơ sở. Bạn có thể sử dụng đối tượng Table để trực tiếp mở bảng được định nghĩa bằng Data Manager ( hoặc vài công cụ định nghĩa cơ sở dữ liệu khác ). Cái chủ yếu thuận lợi của việc sử dụng đối tượng Table là bạn có thể chỉ rõ các chỉ số tìm kiếm và sử dụng phương thức Seek của Visual Basic . Giống như các Dynaset, các Table cũng lấy một lượng giới hạn của trạm nhớ cục bộ.
Các đối tượng Table-type Recordset cũng cho phép bạn thông tin ngay lập tức trên trạng thái của bảng dữ liệu. Đây là vấn đề quan trọng trong môi trường nhiều người sử dụng. Ngay khi một người sử dụng thêm hoặc xoá một bản ghi từ bảng. Tất cả những người sử dụng có bảng mở như một đối tượng Table của Visual Basic cũng nhìn thấy sự thay đổi. Các đối tượng của Visual Basic cũng có các mặt hạn chế của chúng. Bạn không thể sử dụng lệnh Select để khởi tạo một đối tượng Table và bạn không thể phối hợp các bảng để tạo cái nhìn duy nhất của cơ sở dữ liệu khi bạn tạo các đối tượng Table.
Bạn không thể sử dụng các Bookmark, tạo các Filter, hoặc sắp xếp bảng. Hơn nữa bạn không thể sử đối tượng Table để truy cập các dữ liệu nguồn ODBC. Chỉ có các Dynaset và các Snapshot có thể được sử dụng với ODBC.
Các sức mạnh của đối tượng Table-type Recordset.
Sức mạnh thực sự của các đối tượng Table là bạn có thể chỉ rõ các đối tượng Index để sử dụng khi tìm kiếm các bản ghi chỉ rõ trong bảng. Các đối tượng Table cũng sử dụng hạn chế bộ nhớ của trạm làm việc và cung cấp ngay lập tức các cập nhật bất cứ khi nào dữ liệu trong bảng thay đổi. Các Data Pointer và Instant Membership Notification như các Dynaset. Các đối tượng Table sử dụng hạn chế bộ nhớ của trạm làm việc bởi vì Visual Basic cất giữ các pointer đến các bản ghi hiện thời tại trạm làm việc thay vì việc nạp tất cả các bản ghi vào bộ nhớ làm việc. Điều này cho phép chương trình của bạn truy cập tất cả các đối tượng nhanh nhất khi bạn tìm kiếm một bản ghi.
Không như các Dynaset và các Snapshot, các đối tượng Table không là các tập hợp con (subset) của bảng dữ liệu. Chúng chứa tất cả các bản ghi trong bảng tại tất cả thời điểm. Ngay khi một bản ghi mới được thêm vào bảng. Cũng như, ngay khi một user xoá một bản ghi từ bảng. Đối tượng Table cập nhật phản ánh của sự xoá đi. Các đối tượng Table-tupe Recordset, Index và phương thức Seek cho phép bạn chỉ rõ một index để áp dụng đến bảng. Bạn có thể sử dụng các index để sắp xếp các bảng cho việc hiện thị và báo cáo và tốc độ tìm kiếm đang sử dụng phương thức Seek.
Đề án sau ( TBSEEK.VBP ) chứng minh việc sử dụng các đối tượng Table-type Recordset, Index, phương thức Seek của Visual Basic. Nó mở bảng Titles của cơ sở dữ liệu BOOKS5.MDB và cho bạn khả năng một trong ba index. Khi index được lựa chọn, chương trình nạp các bản ghi từ bảng vào một listbox. Khi bạn kích vào nút Search. Bạn lập tức nhập một giá trị tìm kiếm sử dụng phương thức Seek trên bảng.
Sử dụng thông tin trong bảng 3.2 để xây dựng một đề án mới, chứng minh việc sử dụng các đối tượng Table, các Index,phương thức Seek.
Bảng 3.2 : Các điều khiển cho đề án TBSEEK.VBP :
Xem hình 3.6 để tham khảo.
Hình 3.6 :


Chú ý : Bởi vì bạn tạo lại các đối tượng trong mã của Visual Basic trong bài tập này, bạn cần nạp Microsoft DAO 3.5 Object Library.

Каталог: file -> downloadfile5 -> 169
file -> CỘng hòa xã HỘi chủ nghĩa việt nam độc lập Tự do Hạnh phúc
file -> CỘng hòa xã HỘi chủ nghĩa việt nam độc lập Tự do Hạnh phúc
file -> TIÊu chuẩn quốc gia tcvn 7790-5 : 2008 iso 2859-5 : 2005
file -> Qcvn 81: 2014/bgtvt
file -> UỶ ban nhân dân cộng hòa xã HỘi chủ nghĩa việt nam
file -> VIỆn chăn nuôi trịnh hồng sơn khả NĂng sản xuất và giá trị giống của dòng lợN ĐỰc vcn03 luậN Án tiến sĩ NÔng nghiệp hà NỘI 2014
downloadfile5 -> Đề tài báo cáo Thực trạng hoạt động quản trị bán hàng và 1 số giải pháp nhằm nâng cao công tác quản trị bán hàng tại công ty A. D. A
downloadfile5 -> English 12 – Vocabulary + Grammar review cách nhận biết từ loại

tải về 0.58 Mb.

Chia sẻ với bạn bè của bạn:
1   ...   5   6   7   8   9   10   11   12   13




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương