MỚI NHẤT

Thứ Sáu, 27 tháng 6, 2014

Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Ở các bài đăng trước mình đã giới thiệu tới các bạn khái niệm LINQ và cách làm việc với LINQ, đấy là một cách giao tiếp với cơ sở dữ liệu rất thuận tiện và nhanh chóng, dễ dàng cho lập trình viên. Một tính năng đặc biệt quan trọng của "LINQ to SQL" là cách giao tiếp với cơ sở dữ liệu thông qua các biến Context, hỗ trợ code dưới dạng lambda, đơn giản hóa mọi vấn đề, và quan trọng hơn đó là tính năng Binding dữ liệu - đều đã được giới thiệu trong các bài đăng trước.

Microsoft ADO.NET Entity Framework là một khuôn khổ đối tượng Object/ Bảng đồ quan hệ Relational Mapping (ORM) cho phép các nhà phát triển dể dàng làm việc với dữ liệu quan hệ như là các đối tượng domain-specific, loại bỏ đi sự khó khăn trong việc truy cập dữ liệu trước đây. Bằng cách sử dụng Entity Framework, truy vấn LINQ, thì việc lấy và thao tác dữ liệu như các đối tượng trở nên mạnh mẽ hơn. Entity Framework ORM cung cấp các dịch vụ như change tracking, idenity resolution, lazay loading, và truy vấn dữ liệu tập trung vào business logic của ứng dụng.
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL


Đơn giản có thể định nghĩa Entity Framework như sau: Entity Framework là một khung Object/Relational Mapping (O/RM). Nó là một kỹ thuật mới cung cấp cho các nhà phát triển ADO.NET một cơ chế tự động để truy cập và lưu trữ dữ liệu trong cơ sở dữ liệu và làm việc với các kết quả ngoài DataReader và DataSet.
Các bạn có thể đọc thêm về O/RM tại đây.

Việc tại sao lại nên dùng Entity Framework sẽ được lý giải trong phần phân biệt Entity với LINQ to SQL.

I. Entity Framework là gì? Các thành phần của Entity Framework

Entity Framework là một bộ ánh xạ đối tượng – quan hệ cho phép người lập trình .NET  làm việc với dữ liệu quan hệ qua các đối tượng (object) nó giúp lập trình viên không cần viết mã cho (hầu hết) những gì liên quan đến truy cập dữ liệu. 

Các thành phần trong Entity Framework:
Code là mã lệnh tạo thành các lớp đối tượng dữ liệu cho phép thao tác với dữ liệu.
Model là sơ đồ gồm các hộp mô tả các thực thể và các đường nối kết mô tả các quan hệ.
Database là cơ sở dữ liệu (có thể là SQL Server, Compact SQL Server, Local database, MySQL, Oracle,…)

Có 3 cách sử dụng Entity Framework: Code First, Models First, Database First.
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

- Database first: là phương pháp chỉ nên dùng khi ta đã có sẵn CSDL (không phải tạo), EF Wizard sẽ tạo Model và Code cho ta.
- Models first: nên dùng khi ta bắt đầu thiết kế CSDL từ đầu (từ chưa có gì). Ta sẽ thiết kế mô hình CSDL (Model) EF sẽ tự tạo code cho ta, sau đó nhờ EF Wizard tạo CSDL.
- Code first: nên dùng khi đã có mô hình CSDL, ta sẽ chỉ viết code từ đó tạo Database.

Dù cách nào thì cuối cùng cũng phải có Code để thao tác trong mã lệnh và Database để lưu trữ dữ liệu. Model chỉ là một thành phần trung gian.

Theo kinh nghiệm của nhiều lập trình viên đi trước, Code First là phương án mềm dẻo nhất (hơi mất công ngồi gõ code, tuy nhiên nếu dùng tốt code snippets thì đỡ nhiều).

Trước đây khi lập trình CSDL trong VB, VC,… ta luôn tạo CSDL liệu trước, sau đó mới xây dựng mã lệnh truy cập dữ liệu.

Trong bài này tôi sẽ hướng dẫn tạo 1 project Code First với cơ sở dữ liệu có sẵn.

II. Bắt đầu làm việc với Entity Framework

Để làm việc với Entity Framework một cách hoàn chỉnh chúng ta phải cài thêm Entity Framework bản mới nhất từ NuGet:

B1. Tạo Project mới

B2. Cài EF Power Tools vào Visual Studio: Tools -> Library Paskage Manager -> Manage NuGet Packages for Solution…
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Bến trái, chọn Online. Nhập Entity Framework Power Tools vào khung Search (góc trên, bên phải) chọn Entity Framework Power Tools -> Install. 

Khi đã cài được, bạn chuột phải trên tên Project sẽ thấy có menu Entity Framework.

III. Tạo một ứng dụng Entity Code First sử dụng CSDL có sẵn

Code First tức là bạn phải code sau đó sinh Database từ code đó. Nhưng Database tạo ra như thế sẽ ít thuộc tính: ràng buộc, identity, unique... Giải pháp là tạo 1 database hoàn chỉnh trên SQL sau đó viết code để map CSDL với Entity của chúng ta.

Trước hết tạo ra các class mô tả các bảng trong CSDL của chúng ta, nó bao gồm các trường và thuộc tính, kiều của chúng.
public partial class tbLop
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int IdLop { get; set; }

    [StringLength(50)]
    public string Lop { get; set; }
}
public partial class tbHocVien
{
    [Key]
    public int IdHocVien { get; set; }

    public int? IdLop { get; set; }

    [StringLength(50)]
    public string HoTen { get; set; }

    [Column(TypeName = "date")]
    public DateTime? NgaySinh { get; set; }
}

Sau đó tạo 1 class Context - là class quản lý tất cả các bảng và giao tiếp với Entity, nó tương tự như class DataContext trong LINQ to SQL.
public partial class DataContext : DbContext
{
    /// <summary>
    /// Connection string lưu ở App.config
    /// theo name="DataContext"
    /// </summary>
    public DataContext()
        : base("name=DataContext")
    {
    }

    public virtual DbSet<tbHocVien> tbHocViens { get; set; }
    public virtual DbSet<tbLop> tbLops { get; set; }
}

Trong App.config ta thiết đặt ConnectionString để class Conext liên kết với CSDL đã có sẵn.
<connectionStrings>
    <add name="DataContext" connectionString="data source=\SQLEXPRESS;initial catalog=db_EF;persist security info=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>


Cách này rất thủ công và dễ xảy ra sai sót. Để làm việc này chúng ta có thể cài thêm 1 tool của Visual Studio giúp ta tạo Code First từ Database một cách nhanh chóng, chính xác.
Các bạn download tool tại đây
Sau khi tải về và cài đặt, khởi động lại Visual Studio, tạo 1 Entity mới ta sẽ thấy rõ hơn.

Thêm 1 Entity Model, chọn "Code First from Database"
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Chọn Database có sẵn
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Nếu chưa có thì chọn New Connection

Chọn các bảng/view/store để add vào Model
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Sau đó nó sẽ tự sinh ra các class như trên và ConnectionString được lưu trong App.config
Nếu chưa làm được có thể xem tại đây.

Sau khi khai báo các đối tượng của Entity ta có thể sử dụng nó tương tự như đối với LINQ to SQL. Hướng dẫn chi tiết các điểm khác nhau tôi sẽ viết trong 2 bài khác.

IV. So sánh giữa Entity Framework với LINQ to SQL

Sau một thời gian sử dụng Entity tôi rút ra được một số nhận định ban đầu như sau:

LINQ to SQL

- Chỉ làm việc với CSDL của SQL Server
- Tạo ra file .dbml
- Không hỗ trợ các kiểu phức tạp
- Không thể tạo CSDL từ đối tượng
- Chỉ có kiểu ánh xạ 1-1 giữa đối tượng class với table/views
- Sử dụng DataContext

Entity Framework

- Có thể làm việc với các CSDL: Oracle, DB2, MySQL, SQL Server...
- Tạo ra file .edmx, .csdl, .msl, .ssdl hoặc các file class .cs thông thường
- Hỗ trợ các kiểu phức tạp
- Có thể tạo CSDL từ Model/Code đã thiết kế
- Có thể ánh xạ 1-1, 1-nhiều, nhiều-1, nhiều-nhiều giữa đối tượng entity với table/view
- Sử dụng DbContext, Entity SQL, ObjectContext.

Và hơn nữa mô hình Code First sinh ra các class riêng biệt => có thể dễ dàng thay đổi khi thay đổi CSDL

Các câu hỏi thường gặp

1. Hỏi: Tại sao chúng ta cần "Entity Framework" trong khi chúng tôi đã có "LINQ 2 SQL" ?
Trả lời: "Entity Framework" không phải được thiết kế để cạnh tranh với "LINQ 2 SQL", xa hơn nó được thiết kế để nhằm phục vụ một mục đích lớn hơn. Nó là một giải pháp ORM hoàn chỉnh. LINQ Provider chỉ là một khía cạnh của "LINQ 2 SQL"...

2. Hỏi: Nếu "LINQ 2 SQL" không thực sự cần thiết tại sao nó vẫn tồn tại?
Trả lời: Bây giờ, tôi không thể chính thức trả lời câu hỏi này (tôi không là đại diện cho Microsoft) nếu bạn nhìn vào sự tiến hóa về các framework và những bản phát hành của họ thì có thể không có kết hợp lý nào khác hơn so với những trình bày ở đây

Microsoft, có lẽ chưa từng có ý định đưa "LINQ 2 SQL" như là một giải pháp hoặc một framework. Có lẽ Entity framework chưa thật sự sẵn sàng tại thời điểm mà .Net 3.5 xuất xưởng. Microsoft đã đưa "LINQ 2 SQL" ra như một giải pháp điểm dừng của cách biệt hoặc chỉ đơn thuần là một mẫu cho "LINQ provider". Họ cuối cùng đã đưa ra Entity Framework với. Net 3.5 SP1. Tôi thật sự cảm thấy Entity Framework đã trở thành một thành phần của bản phát hành chỉnh thức và không phải là một phần của một gói dịch vụ. Không thể có hai nghi ngờ rằng Entity Framework là cách đề nghị đầy tham vọng cho việc truy cập dữ liệu và LINQ.

3. Hỏi: Vậy có phải kết luận rằng chúng ta nên thay thế tất cả "LINQ 2 SQL" với "Entity Framework".
Trả lời: Điều này dường như có vẻ là một kết luận hợp lý và cần phải được thực hiện trong thời gian dài. Tuy nhiên, dường như bản phát hành hiện tại của Entity Framework là chưa thật sự sẵn sàng cho nhu cầu doanh nghiệp và có lẽ chúng ta cần phải chờ ở bản phát hành của Net 4.0. Một số thử nghiệm độc lập đã cố gắng để chứng minh "LINQ 2 SQL" trong thực hiện của Entity Framework. Tôi đã không thực hiện các thử nghiệm cho một trong hai xác nhận hay mâu thuẫn với việc nghiên cứu của họ, mà chỉ chờ đợi ở phiên bản .Net 4.0.
Xem thêm tại đây.

Nguồn tham khảo: tổng hợp từ Internet.

Thứ Sáu, 13 tháng 6, 2014

[WindowForm] Làm việc với GridView - Grid Control của DevExpress

Trong bài "[LINQ] LinQ là gì và tại sao nên dùng LinQ?" tôi đã giới thiệu đến các bạn sơ qua về LINQ và Binding, trong đó có 1 thành phần quan trọng đó là GridView của DevExpress. GridView có vai trò rất quan trọng trong việc hiển thị các dữ liệu dạng bảng, danh sách trong các phần mềm quản lý danh mục... và là thành phần không thể thiếu trong Binding dữ liệu.
Ở lần trước tôi chỉ giới thiệu các bạn về cách kéo thành phần GridView tự động từ cửa sổ "Data Source" phục vụ việc Binding, trong bài này tôi sẽ hướng dẫn cách làm việc với GridView thủ công, tùy chỉnh giao diện của nó - một trong những tính năng vượt trội, thành công lớn của DevExpress.

I. Tạo và thiết lập nguồn dữ liệu cho GridView

Tạo đối tượng GridView - Grid Control

Để tạo 1 đối tượng các bạn search trong toolbox "GridControl" và kéo vào form
Làm việc với GridView - Grid Control của DevExpress

Thiết lập nguồn dữ liệu cho GridView

Bây giờ chúng ta sẽ khai báo nguồn dữ liệu (data source) cho GridView, để gridview tự động lấy các giá trị và fill vào. Đây là tiện ích lớn nhất của việc Binding: có thể tự động lấy các dữ liệu điền vào grid và liên kết với phần detail
Để chọn data source cho gridView ta click vào hình tam giác ở góc trên cùng bên phải GridView. Trong phần "Choose Data Source" ta chọn data source đã có sẵn hoặc click chọn "Add Project Data Source" nếu chưa có.
Làm việc với GridView - Grid Control của DevExpress

Khi chọn Add Project Data Source các bạn có thể chọn thêm 1 database, service, object, sharepoint nhưng bạn nên chọn object để nó có thể kết nối tới file ".dbml" đã tạo trong phần giới thiệu LINQ.
Làm việc với GridView - Grid Control của DevExpress

Sau khi chọn object ta sẽ chọn bảng/view/đối tượng làm datasource cho GridView. GridView sẽ tạo ra các cột tương tự như các trường của bảng/view/đối tượng đã chọn.
Làm việc với GridView - Grid Control của DevExpress

Bây giờ chỉ cần thêm một vài câu lệnh để set nguồn dữ liệu thực cho datasource này. Việc này đã được giới thiệu trong bài giới thiệu LINQ.

Lưu ý:

  • Data Source cho GridView không chỉ là 1 table/view thực trong database mà có thể là 1 object ảo các bạn tạo ra trong file ".dbml" hoặc 1 đối tượng của Dataset... Với những object ảo này các bạn có thể tùy chỉnh, xử lý dữ liệu cho GridView.

II. Phần giao diện của GridView

Để tùy chỉnh giao diện, dữ liệu trong các hàng/ô của GridView ta có thể xem trong cửa sổ "Properties" tương ứng của GridView hoặc đơn giản hơn có thể mở giao diện tùy chỉnh của DevExpress:
Làm việc với GridView - Grid Control của DevExpress

Trong phần "Run Designer" này các bạn có thể tùy chỉnh một số thuộc tính của header, phần hiển thị của các ô, việc sửa đổi dữ liệu trong ô, sắp xếp theo cột, thay đổi màu sắc, font chữ... và cả các kiểu hiển thị dữ liệu trong từng ô. Chẳng hạn:

1. Tùy chỉnh giao diện

Thêm/bớt, thay đổi thứ tự các cột

Làm việc với GridView - Grid Control của DevExpress

Với "gridView1" ta vẫn có các sự kiện như ở GridView thông thường như: RowClick, RowCellClick...
Làm việc với GridView - Grid Control của DevExpress


Tùy chỉnh Layout

Làm việc với GridView - Grid Control của DevExpress

Thay đổi font chữ, căn lề của header, ô trong từng cột


Ấn giữ Ctrl để chọn nhiều cột 1 lúc. Các thuộc tính trong phần AppearanceCell & AppearanceHeader như font, Col Name, Text Options, Filter, Allow Edit, Visible... 

Phân biệt hàng chẵn, lẻ

Trong tab Views, phần Appearance > EvenRow, OddRow ta có thể thay đổi một số thuộc tính như màu nền, font chữ, text options... như ở phần header:
Làm việc với GridView - Grid Control của DevExpress

Kéo xuống phần OptionsView, chọn EnableApearanceEvenRow hoặc EnableApearanceOddRow bằng true
Làm việc với GridView - Grid Control của DevExpress

2. Kiểu dữ liệu hiển thị trong ô

Mặc định khi ta chọn Data Source cho GridView thì các cột trong GridView sẽ có 1 kiểu hiển thị dữ liệu tương ứng với kiểu dữ liệu của data source. Chẳng hạn nếu ở kiểu dữ liệu data là nvarchar thì control edit dữ liệu là textEdit (của Dev)... 
Giả sử bây giờ ta có 1 cột là idNhanVien nhưng ta muốn nó hiển thị là Họ tên của Nhân viên thì phải làm thế nào??!

Bằng cách dùng bảng NhanVien để tham chiếu từng idNhanVien với HoTen tương ứng ta sẽ lấy được họ tên của nhân viên ứng với id. Chắc hẳn việc này là rất khó khăn nếu ta dùng code thông thường, không dùng Binding vì phải tương tác qua lại giữa idNhanVien và HoTen trong tất cả các công việc sau này. Khi đã có Binding + DevExpress thì việc đó trở lên tương đối easy.

Ở Run Desinger, tab Columns, với cột tương ứng ta  chỉ cần thêm 1 đối tượng "ColumnEdit" tương ứng với kiểu dữ liệu, trường thông tin muốn hiển thị. Chẳng hạn muốn hiển thị họ tên của nhân viên, vì đây là trường có sẵn (chỉ việc select), số lượng có thể rất nhiều nên ta chọn ColumnEdit là một đối tượng SearchLookupEdit (giống kiểu ComboBox nhưng có tìm kiếm của Dev). Hay như với cột ghi thông tin ghi chú (độ dài nhỏ) thì ta có thể chọn là TextEdit để sau này có thể sử dụng các thuộc tính của TextEdit như MaxLength, Mask...

Quay trở lại với bài toán của chúng ta, sau khi đã thêm đối tượng SearchLoopupEdit cho cột idNhanVien thì ta có 1 đối tượng SearchLookupEdit thông thường, có thể đặt Data Source cho nó, trường hiển thị (DisplayMember), trường giá trị tương ứng (ValueMember). Ở đây ta đặt Data Source là 1 đối tượng trong file ".dbml" tham chiếu đến bảng NhanVien, DisplayMember là HoTen, ValueMember là idNhanVien.
Làm việc với GridView - Grid Control của DevExpress

Sau khi đặt ...bindingSource.DataSource = bla bla; thì kết quả được như này
Làm việc với GridView - Grid Control của DevExpress

Như vậy đã hiển thị được họ tên nhân viên và chức vụ tương ứng mà không cần dùng quá nhiều code, trong khi đó khi cần thiết vẫn có thể lấy được các giá trị id một cách dễ dàng.

Bây giờ nảy sinh một vấn đề nữa là khi ta edit cái SearchLookUp vừa tạo ở trên nó có giao diện không đẹp lắm, đặc biệt phiền phức nếu cái bảng nhân viên có vài chục trường mà ta chỉ muốn hiển thị một vài trường như họ tên, quê quán...
Như này chẳng hạn
Làm việc với GridView - Grid Control của DevExpress

Tất nhiên các kiểu hiển thị này chỉ cần quan tâm khi ta để dữ liệu ở cột dạng AllowEdit.

Để tùy chỉnh cũng không có gì quá phức tạp, chỉ là trên cái giao diện rối rắm vì quá nhiều chức năng của DevExpress khiến ta bối rối. Trong phần Columns > cột cần thay đổi > ColumnEdit (vừa tạo ở trên) > View
Làm việc với GridView - Grid Control của DevExpress

Để đơn giản ta click vào biểu tượng dấu 3 chấm "...". Nó sẽ ra một cửa số mới để tùy chỉnh cái SearchLookupEdit này tương tự với cái tùy chỉnh GridView ta làm việc từ đầu đến giờ.
Ta cũng có thể tùy chỉnh Layout, thêm/bớt cột, đặt caption, thay đồi font chữ header, phân biệt hàng chẵn/lẻ...
Làm việc với GridView - Grid Control của DevExpress

Và kết quả cuối cùng:
Làm việc với GridView - Grid Control của DevExpress

Enjoy!!!

Thứ Tư, 23 tháng 4, 2014

[SQLExpress] Lấy bản ghi ngẫu nhiên với SQL và LinQ

Trong nhiều trường hợp ta phải chọn ngẫu nhiên 1 hoặc một số bản ghi trong CSDL như: chọn 5 bài đăng ngẫu nhiên trong blog, chọn 1 câu hỏi ngẫu nhiên cho chương trình trả lời câu hỏi...
Trong cú pháp của SQL, LinQ đều có cách để làm việc này

I. SQL query lấy bản ghi ngẫu nhiên

Lấy bản ghi ngẫu nhiên với SQL và LinQ

Cấu trúc
SELECT TOP 5 [IDpost]
  FROM [dbo].[tbPost]

  ORDER BY NEWID()  -- Trình tự sắp xếp ngẫu nhiên

Trong đó NEWID() quy định 1 trình tự sắp xếp mà các bản ghi được sắp xếp ngẫu nhiên, đây chính là cơ sở để lấy các bản ghi ngẫu nhiên.

II. Lấy bản ghi ngẫu nhiên bằng code LINQ

Dùng phương thức SKIP() của IEnumerable để nhảy qua n bản ghi, với n là một số ngẫu nhiên. Thực chất cách này không phải là lấy ngẫu nhiên một số bản ghi mà nếu có thì cũng chỉ hiệu quả với bài toán lấy ngẫu nhiên 1 bản ghi duy nhất.
Lấy bản ghi ngẫu nhiên với SQL và LinQ

Cấu trúc của cách làm này như sau:
var p = from post in db.tbPosts
  select new { post.IDpost, post.title };  // Chọn dữ liệu từ LinQ

int count = p.Count();
var random = new System.Random();                   // Khởi tạo biến random
var postRD = p.Skip(random.Next(count)).Take(5);    // Tiến hành random và chọn 5 record đầu tiên
dataSet1BindingSource.DataSource = postRD;          // Điền dữ liệu vào datagridview

Theo code này thì bạn sẽ lấy được 5 bản ghi liền nhau ở vị trí ngẫu nhiên > sẽ có lúc nhận được không đủ 5 bản ghi. Không đúng với bài toán lắm.
Vậy giải pháp ở đây là chạy câu lệnh SQL chửa NEWID() bằng LINQ
var postRD = db.ExecuteQuery<tbPost>("SELECT * FROM tbPost ORDER BY NEWID()").Take(5);
dataSet1BindingSource.DataSource = postRD;          // Thiết lập dữ liệu cho binddingridview


Chủ Nhật, 20 tháng 4, 2014

[LINQ] LinQ là gì và tại sao nên dùng LinQ?

Với SQLExpress để truy vấn dữ liệu ta phải dùng đến các câu lệnh - Query khá phức tạp. Hơn nữa để sử dụng trong ứng dụng C# lại thêm 1 tầng phức tạp nữa với các câu lệnh: dùng ConnectionString khởi tạo kết nối tới DataBase, tự khai báo các biến để chạy 1 lệnh - command, rồi còn phải tính toán đầu ra của câu lệnh... Thật là quá phức tạp nếu như ta có 1 chương trình "khủng".
Vậy làm sao để giải quyết vấn đề này? 
Một đề xuất là sử dụng Linq to SQL.
Không chỉ áp dụng cho truy vấn SQL mà LinQ còn có khả năng hỗ trợ trên nhiều nền tảng khác: XML, SQLite, Excel...

I. LinQ là gì?

LinQ là gì và tại sao nên dùng LinQ

Để giảm gánh nặng thao tác trên nhiều ngôn ngữ khác nhau và cải thiện năng suất lập trình, Microsoft đã phát triển giải pháp tích hợp dữ liệu cho .NET Framework có tên gọi là LINQ (Language Integrated Query), đây là thư viện mở rộng cho các ngôn ngữ lập trình C# và Visual Basic.NET (có thể mở rộng cho các ngôn ngữ khác) cung cấp khả năng truy vấn trực tiếp dữ liệu Object, CSDL và XML.
LINQ là một tập hợp các thành phần mở rộng cho phép viết các câu truy vấn dữ liệu ngay trong một ngôn ngữ lập trình, như C# hoặc VB.NET. Khi tạo một đối tượng LINQ thì Visual Studio sẽ tự động sinh ra các lớp có các thành phần tương ứng với CSDL của chúng ta. Khi muốn truy vấn, làm việc với CSDL ta chỉ việc gọi và truy xuất các hàm, thủ tục tương ứng của LINQ mà không cần quan tâm đến các câu lệnh SQL thông thường.
Tóm lại LINQ ra đời để giảm công sức cho những quá trình đơn giản và “chung chung” trước đây.

Điểm mạnh (chưa chắc về độ mạnh, nhưng hay) của LINQ là “viết truy vấn cho rất nhiều các đối tượng dữ liệu”. Từ CSDL, XML Data Object … thậm chí là viết truy vấn cho một biến mảng đã tạo ra trước đó. Vì vậy mới có các khái niệm LinQ to SQL, LinQ to XML, blo bla ….
Tuy nhiên so với mô hình Entity (Entity Framework), LINQ có yếu điểm là chậm và thiếu nhất quán (hiện đại tất phải hại điện).

LINQ có từ bản .NET 3.5, vậy nên tối thiểu chương trình của bạn phải chạy trên nền tảng này.
Visual Studio 2008, hoặc các phiên bản Express của nó là các bộ công cụ phát triển tiêu biểu cho ứng dụng dùng LINQ.

II. Sử dụng LinQ

LinQ là gì và tại sao nên dùng LinQ
Câu lệnh SELECT trong SQL được thực hiện bởi LINQ
Trong phần này tôi sẽ sử dụng 1 project demo để các bạn thấy được cách làm việc với LINQ như thế nào?!
CSDL là 1 bảng tbTest với 2 trường: id (kiểu int, tự động tăng - Identity) và Feild1 (kiểu nvarchar(50)).

1. Khởi tạo đối tượng LinQ to SQL

Trong project chọn Add > Data > LinQ to SQL classes

LinQ là gì và tại sao nên dùng LinQ?

Ở đây tôi tạo 1 file DB.dbml trong thư mục DB để dễ quản lý.
Sau khi có được file ta tiến hành kéo các table cần thiết vào để tự động sinh các thủ tục LinQ
LinQ là gì và tại sao nên dùng LinQ?

Vậy là xong, ta đã tạo được các thủ tục cần thiết để làm việc với LINQ. Easy??!!   :)

2. Truy vấn dữ liệu

Tương tự như Entity ta phải khai báo 1 biến DataContext để tương tác với LinQ
DB.DBDataContext db = new DB.DBDataContext();  

Có 2 kiểu truy vấn dữ liệu:
Query Syntax
var abc = from p in db.tbTests
          where p.id > 10
          select p;

// Hoặc chọn một số trường
var abc = from p in db.tbTests
          where p.id > 10
          select new
          {
              p.id,
              p.Feild1
          };
Method Syntax
var xyz = db.tbTests.Where(p => p.id > 10).Select(p => new { p.id, p.Feild1 });

Câu truy vấn SQL tương ứng
SELECT [id]
      ,[Feild1]
  FROM [dbo].[tbTest]
  WHERE [id] > 10

Chọn từ nhiều bảng theo kiểu Inner Join (lấy những bản ghi có điều kiện thỏa mãn)
// Query Syntax
var result = from p in products
             join c in categories on p.CategoryID equals c. CategoryID
             select new
             {
                 ProductName=p.ProductName,
                 CategoryName=c.CategoryName
             };

// Hoặc chọn từ 2 bảng bằng cách from 2 lần  :)
var result = from p in products
             from c in categories
             where p.ProductName equals c.CategoryName
             select new
             {
                 ProductName=p.ProductName,
                 CategoryName=c.CategoryName
             };

// Method Syntax
var result = products.Join(
             categories,
             p=>p.CategoryID,
             c=>c.CategoryID,
             (p,c) => new
             {
                 ProductName=p.ProductName,
                 CategoryName=c.CategoryName
             });

Cú pháp khác tương tự các câu lệnh trong SQL.
Các biến ở trên trả về có kiểu IEnumrable, 1 loại kiểu dữ liệu giống như List. Các thao tác cơ bản với loại biến này:

  • xyz.FirstOrDefault(): Chọn bản ghi đầu tiên hoặc mặc định
  • xyz.Skip(5): Nhảy qua n bản ghi
  • xyz.Take(5): Lấy n bản ghi đầu tiên
  • xyz.ToList(): Chuyển sang kiểu List
  • xyz.Count(): đếm số bản ghi
  • xyz.Select(...), xyz.Where(...), xyz.Join(...): Các câu lệnh truy vấn theo kiểu Method Syntax
  • bla bla

Đôi khi bạn không tìm được cú pháp thích hợp hoặc LinQ không hỗ trợ loại truy vấn mà vốn có trong SQL thì bạn có thể thực hiện trực tiếp câu lệnh đó thông qua LinQ:
var result = db.ExecuteQuery<int>("SELECT NEXT VALUE FOR seq_tbCanBo")

3. Thêm, sửa, xóa dữ liệu thông qua LinQ

Thêm dữ liệu
DB.tbTest a = new DB.tbTest();      // Khai báo đối tượng mới
a.Feild1 = txtFeild1.Text;      // id là giá trị tự động tăng > ko cần thay đổi
db.tbTests.InsertOnSubmit(a);   // Thêm đối tượng a vào
db.SubmitChanges();     // Lưu thay đổi

Sửa dữ liệu
var a = (from p in db.tbTests
         where p.id == int.Parse(txtId.Text)
         select p).FirstOrDefault();
a.Feild1 = txtFeild1.Text;
db.SubmitChanges();

Xóa dữ liệu

var a = (from p in db.tbTests
         where p.id == int.Parse(txtId.Text)
         select p).FirstOrDefault();
db.tbTests.DeleteOnSubmit(a);
db.SubmitChanges();

III. Bindding

Bindding là cách thuận tiện để thay đổi, cập nhật, thêm mới bản ghi ở CSDL một cách dễ dàng trực quan, sử dụng LinQ.
Giả sử ta thực hiện Bindding ở 1 bảng, có 2 chế độ (kiểu hiển thị) là GridView Detail:
  • Chế độ GridView: có 1 gridview để hiển thị các bản ghi trong bảng, tương tự như khi chúng ta chạy câu truy vấn SELECT * trong SQL
  • Detail: các Control cho phép thay đổi giá trị của bản ghi đang được chọn ở Gridview. Khi click vào 1 hàng ở Gridview thì dữ liệu của hàng đó sẽ được điền tự động vào các Control này.

Cách dùng Bindding:
Trong chế độ Design form, mở cửa sổ Data Sources, ở đây các bảng trong file DB.dbml (được tạo khi khởi tạo LinQ) sẽ được hiển thị, giúp ta có thể kéo vào trong form của mình
Với mỗi bảng có các tùy chọn để chọn chế độ xem: Gridview, Detail,...
LinQ là gì và tại sao nên dùng LinQ?
Tạo Bindding bằng cách kéo thả
Sau khi kéo như vậy thì nó sinh ra 1 đối tượng là tbTestBinddingSource, đây chính là đối tượng tương tác với SQL, LinQ.
Quy định nguồn dữ liệu cho Bindding:
// DataSource là 1 bảng có sẵn
tbTestBindingSource.DataSource = db.tbTests;

// Datasource là một đối tượng IEnumrable lấy từ truy vấn LINQ
tbTestBindingSource.DataSource = result;

Bạn có thể kéo 1 BinddingNavigator để thực hiện các thao tác thêm, xóa dễ dàng
LinQ là gì và tại sao nên dùng LinQ?

Khi đã có Bindding như thế này rồi thì việc thêm sửa xóa cực kỳ đơn giản, không cần code nhiều, sau khi thay đổi trên gridview, detail để lưu tất cả các thay đổi chỉ cần
tbTestBindingSource.EndEdit();
db.SubmitChanges();

Các thao tác có thể làm với BinddingSource
tbTestBindingSource.RemoveCurrent();    // Xóa hàng hiện tại

// Di chuyển trên gridview
tbTestBindingSource.MoveFirst();
tbTestBindingSource.MoveLast();
tbTestBindingSource.MoveNext();
tbTestBindingSource.MovePrevious();

tbTestBindingSource.Position = 5;   // Xác định vị trí cho Bindding

Sau số thao tác thay đổi trên grid view, bạn muốn xem số hàng thêm mới, sửa xóa??
int insert = db.GetChangeSet().Inserts.Count;
int update = db.GetChangeSet().Updates.Count;
int delete = db.GetChangeSet().Deletes.Count;


Tham khảo project demo trên tại đây.
Các bạn có thể truy cập liên kết để có thêm thông tin, các thao tác với LINQ.

Thứ Năm, 10 tháng 4, 2014

Giới thiệu ASP MVC - Hướng dẫn cơ bản để tạo một website ASP MVC đầu tiên (P2)

Trong bài Giới thiệu ASP MVC - Hướng dẫn cơ bản để tạo một website ASP MVC đầu tiên (P1) tôi đã giới thiệu với các bạn sơ qua về ASP.NET MVC và cách tạo một trang web MVC đơn giản. Trong phần 2 này tôi sẽ giúp bạn code 1 vài trang cho web site và 1 vài tiện ích liên quan tới MVC.

I. Tổ chức code MVC

Đầu tiên là trang chủ - trang hiển thị thông tin các sản phẩm. Vì yêu cầu trả về thông tin sản phẩm + loại sản phẩm, tức là lấy thông tin từ 2 bảng khác nhau vì thế ta khai báo thêm 1 class có các trường: ID, TenSP, TenLSP như sau:
public class Product
    {
        public int ID { get; set; }
        public string TenSP { get; set; }
        public string TenLoaiSP { get; set; }
    }
Trong DefaultController, để làm việc với DB Entity ta khai báo 1 biến toàn cục để sử dụng trong tất cả các Action:
SanPhamDB db = new SanPhamDB(); // SanPhamDB là tên Database, db là biến Entity
Controller thực hiện các câu lệnh và trả về kết quả cho browser thông qua View. Để có thể làm được điều đó ta phải khai báo 1 hàm có kiểu trả về là ActionResult (các hàm kiểu này có nhiều loại kiểu trả về, đọc tài liệu đính kèm để biết thêm chi tiết). Cụ thể với phần Index của dự án này (hiển thị thông tin sản phẩm, loại sản phẩm) có phần code như sau:
#region Trang chủ
        public ActionResult Index()
        {
            // Entity
            // LINQ
            // //Query syntax:
            var product = (from p in db.tbSanPhams select p).ToList(); // Biến danh sách chọn từ Database tbSanPham

            List<Product> prod = new List<Product>(); // Khai báo ‘prod’ là kiểu List các Product (Product là class khai báo ở trên)
            
            for (int i = 0; i < product.Count(); i++)
            {
                Product p = new Product();
                p.ID = product[i].Id;
                p.TenSP = product[i].TenSanPham;

                int type = product[i].LoaiSanPham; // Lấy ID loại sản phẩm của sản phẩm ‘i’ 

                // LInQ 
                // Method systax
                var p2 = (db.tbLoaiSanPhams.Where(p1 => type == p1.LoaiSanPham).Select(p1 => p1.TenLoaiSanPham)).ToList();
// Chọn tên loại sản phẩm từ bảng ‘tbLoaiSanPham’ với điều kiện ‘LoaiSanPham’ ở 2 bảng bằng nhau.

                p.TenLoaiSP = p2[0];
                prod.Add(p); // Thêm ‘p’ vào List ‘prod’
            }
            return View(prod);
        }
#endregion
Giao diện trang Index (hiển thị danh sách các sản phẩm)

Lưu ý:
  • Kiểu List() là kiểu danh sách tương tự như Array nhưng nó linh hoạt hơn Array: không cần phải khai báo số phần tử của mảng, có các hàm, thủ tục: Add, Sort
  • Có hai loại sử dụng cú pháp Entity (LINQ):
    Query syntax: Cú pháp la lá giống SQL
    Method systax: Cú pháp theo kiểu các class được khai báo sẵn: db.tb.Where(…).Select… Điểm chú ý là các biến của kiểu khai báo này không có sẵn, do đó ta phải khai báo chúng trực tiếp trong câu lệnh. Ví dụ: db.tbLoaiSanPhams.Where(p1 => type == p1.LoaiSanPham).Select(p1 => p1.TenLoaiSanPham). Trong đó khai báo biến là p1.
  • Còn #region #endregion chỉ đơn giản là tạo ra 1 khu vực với nhiệm vụ nhất định, trong này ta có thể khai báo nhiều hàm, thủ tục khác nhau. Sau này ta có thể thu gọn các khu vực này để code trông đơn giản, dễ nhìn hơn
Để trả về thông tin cho HTML ta phải sử dụng View().
View là phần hiển thị thông tin được sử lý dựa vào thông tin trả về từ Controller. View cũng tương tự như các trang HTML thông thường. View cũng có thể dùng các trang Master (như ASP Webform) hoặc Layout (ở Razor)
View phải có tên giống với tên hàm tương ứng ở Controller. Như trên ta phải tạo 1 view có tên là Index.aspx hoặc Index.cshtml
Để tạo view nhanh ta trỏ con trỏ đến tên hàm, ấn Ctrl M >> Ctrl V.

Lưu ý hàm trên trả về 1 giá trị là ’View(prod);

II. Cách trả dữ liệu về View để hiển thị ra trình duyệt

 1.  Trả về dưới dạng Dynamic Data tức là bằng ViewBag.<name> hoặc ViewData[“<name>”]; trong đó <name> là tên tùy ý do lập trình viên đặt (ta nên đặt chúng theo đúng quy cách, hạn chế các trường hợp đặc biệt…). Hai dạng này có chức năng, cách dùng tương tự nhau. Ở Controller gán giá trị cho chúng như 1 biến thông thường mà không cần phải khai báo
ViewBag.Sloaisp = “Hello”;
ViewData[“Sloaisp”] = “Hello”;
Ở View ta lấy các giá trị này như sau:
ASP: <%= ViewBag.Sloaisp %>   <%= ViewData[“Sloaisp”] %> 
Razor: @ViewBag.Sloaisp;  @ViewData[“Sloaisp”]

2.  Trả về dữ liệu có cấu trúc: 
Như hàm trên trả về 1 List giá trị có kiểu Product. View sẽ nhận List này rồi xử lý, trả về HTML tương ứng Cụ thể trong phần khai báo của aspx ta khai báo như sau:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/View.Master" Inherits="System.Web.Mvc.ViewPage<DEMOmvc.Models.Product>" %>
Trong phần thân ta lấy thông tin “prod” như sau:
<% foreach(var item in Model)
{ %><%= item.ID %>

<%= item.TenSP %>  

<%= item.TenLoaiSP %>  

<%= Html.ActionLink("Sửa", "Edit", new { ID = item.ID }) %> | <%= Html.ActionLink("Xóa", "Delete", new { ID = item.ID })%>

<% } %>

Với các trang Edit, Delete, New ta cũng thực hiện tương tự.




III. LinQ và làm việc với LinQ

          LinQ là một cách giao tiếp với CSDL. Nó giúp ta làm việc với CSDL một cách ra dễ dàng thông qua những hàm, thủ tục được khai báo sẵn. LinQ giúp ta dễ dàng trong việc sử dụng Bindding sau này.

Trong nội dung bài viết này tôi sẽ sử dụng LinQ và biến SanPhamDB db được khai báo ở trên.

- Thêm một bản ghi vào bảng:
tbSanPham SP = new tbSanPham(); // Khai báo class “SP” có kiểu tbSanpham  (tương ứng với tên bảng do Entity tự động tạo ra)

string TenSP = Fcollect["TenSP"]; // Lấy thông tin từ Form HTML chuyển vào, khi có hàm ActionResult phải nhận 1 tham số tương ứng: “FormCollection Fcollect”

int LoaiSP = int.Parse(Fcollect["LoaiSP"]);
SP.TenSanPham = TenSP; // Thêm thông tin vào biến SP
SP.LoaiSanPham = LoaiSP;
db.tbSanPhams.Add(SP); // Thếm biến SP vào List tbSanPhams
db.SaveChanges(); // Lưu lại

- Sửa bản ghi có Id = ID:
tbSanPham SP = db.tbSanPhams.First(m => m.Id == ID); // Lấy bản ghi đầu tiên có Id bằng ID truyền vào từ HTML (viết theo kiểu Method Syntax)

SP.TenSanPham = TenSP; // Sửa các thông tin lấy từ HTML
SP.LoaiSanPham = LoaiSP;
UpdateModel(SP);
db.SaveChanges();

- Xóa 1 bản ghi có Id = ID
tbSanPham SP = db.tbSanPhams.First(m => m.Id == ID);
db.tbSanPhams.Remove(SP);
db.SaveChanges();

Trên đây là các thao tác cơ bản để làm việc với LinQ, bạn có thể tham khảo.


IV. Rewrite URL trong MVC

        Các Controller, View đã được tạo vậy nó sẽ được map đến địa chỉ URL như thế nào???
Các thông tin về URL được quy định trong RouteConfig.cs trong thư mục App_Start. Trong hàm RegisterRoutes ta khai báo như sau:
routes.MapRoute(
                name: "Default1",
                url: "{action}/{ID}",
                defaults: new { controller = "Default", action = "Index", ID = 0 }
);
routes.MapRoute(
                name: "Default",
                url: "{action}.html",
                defaults: new { controller = "Default", action = "Index" }
);

Mỗi cái đăng ký Route có các tham số: Tên, địa chỉ URL, action và các tham số mặc định…
Bằng cách này bạn có thể tạo ra những địa chỉ "thân thiện" cho website của mình.

Chúc bạn thành công!