LinQ trong .NET framework

Ngôn ngữ truy vấn LINQ

Trước đây ta từng biết trong các hệ cơ sở dữ liệu ta có thể thực hiện các câu lệnh truy vấn như from, where, select,... Đã bao giờ bạn nghĩ rằng ta có thể sử dụng các câu truy vấn này áp dụng vào các object, xml, json nói chúng hay các trong table, entity trong ASP .NET nói riêng ? 😗

Do đó, Microsoft mới nghĩ ra việc xây dựng 1 ngôn ngữ truy vấn nào đó mà có thể dùng cho tất cả nguồn dữ liệu, tất cả các định dạng dữ liệu khác nhau. Ngôn ngữ truy vấn đó là LINQ.!

1. Những điều cần biết về LinQ

1.1. Khái niệm 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 hiệu 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à VB.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 của Object, cơ sở dữ liệu, XML hay là các entity trong ASP .NET
  • Điểm mạnh của LINQviết truy vấn cho rất nhiều các đối tượng dữ liệu. Từ cơ sở dữ liệu, XML, Data Object,... thậm trí là viết truy vấn cho các mảng do người dùng tạo ra nhử mảng số, ký tự hay là các mảng đối tượng do người dùng tự định nghĩa

1.2. Các thành phần của 1 hoạt động truy vấn với LINQ

  • Tất cả các hoạt động truy vấn LINQ đều bao gồm 3 tác vụ:

    • Kết nối với nguồn dữ liệu (data source)
    • Tạo truy vấn
    • Thực thi truy vấn

2. Các thành phần trong LINQ

2.1. LINQ to Objects

"LINQ to Object" ở đây nói đến cách sử dụng LINQ đối với các đổi tượng Collection mà đã được thực thi ở giao diện IEnumerable hoặc IEnumerable<T> tức là nhưng Collection có thể "liệt kê" ra được. Đây là trường hợp sử dụng đơn giản nhất của LINQ khi làm việc với dữ liệu.

VÍ dụ trong console:

using System;
using System.Collections.Generic;
using System.Linq;

namespace LINQtoObjects {
   class Department {
      public int DepartmentId { get; set; }
      public string Name { get; set; }
   }

   class LinqToObjects {
      static void Main(string[] args) {
      
         List<Department> departments = new List<Department>();
			
         departments.Add(new Department { DepartmentId = 1, Name = "Account" });
         departments.Add(new Department { DepartmentId = 2, Name = "Sales" });
         departments.Add(new Department { DepartmentId = 3, Name = "Marketing" });

         var departmentList = from d in departments
                              select d;

         foreach (var dept in departmentList) {
            Console.WriteLine("Department Id = {0} , Department Name = {1}",
               dept.DepartmentId, dept.Name);
         }
		 
         Console.WriteLine("\nPress any key to continue.");
         Console.ReadKey();
      }
   }
}

ở trên mình đã sử dụng cú pháp LINQ:

var departmentList = from d in departments
                              select d;

để lấy tất cả các dữ liệu từ mảng object, hãy thử sử dụng cùng các điều kiện where xem nhé 😀

2.2. LINQ to SQL

LINQ to SQL là một phiên bản hiện thực hóa của O/RM (object relational mapping) có bên trong .NET Framework 3.5, nó cho phép bạn mô hình hóa một cơ sở dữ liệu dùng các lớp .NET. Sau đó bạn có thể truy vấn cơ sở dữ liệu dùng LINQ, cũng như cập nhật/thêm/xóa dữ liệu từ đó. LINQ to SQL hỗ trợ đầy đủ transaction, view và các stored procedure (SP). Nó cũng cung cấp một cách dễ dàng để thêm khả năng kiểm tra tính hợp lệ của dữ liệu và các quy tắc vào trong mô hình dữ liệu của bạn.

2.3. LINQ to XML

Sử dụng LINQ với mục đích truy vấn file XML và tiện lợi truy vấn hơn nhiều so với việc dùng XmlDocument, Xpath và Xquery như trước kia. 👍

2.4. LINQ to Datasets

Giới thiệu sơ về DataSet DataSet trong ADO .NET là một bước phát triển lớn trong việc phát triển ứng dụng cơ sở dữ liệu đa hệ. Khi lấy và chỉnh sửa dữ liệu, duy trì liên tục kết nối tới Data Source trong khi chờ user yêu cầu thì rõ ràng là tốn tài nguyên máy rất nhiều.

DataSet giúp ích ở đây rất lớn. Vì DataSet cho phép lưu trữ dữ liệu và chỉnh sửa tại ‘local cache’, hay gọi là offline mode. Có thể xem xét và xử lý thông tin trong khi ngắt kết nối. Sau khi chỉnh sửa và xem xong thì tạo một kết nối và update dữ liệu từ local vào Data Source. Dữ liệu trong DataSet được lưu trữ dưới dạng một Collection các Tables và bạn cần phải xử lý thông qua các lớp DataTable (DataRow và DataColumn).

Về phần này mình sẽ làm 1 ví dụ cụ thể trong ASP .NET bên dưới 👇

3. Ví dụ về sử dụng LINQ trong ASP .NET

3.1. Khởi tạo project

  • Mình sẽ tạo 1 project ASP .NET MVC

  • Tiếp theo ta sẽ tạo model dữ liệu Product trong thư mục model như sau:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace LINQAspDemo.Models {
    public class Product {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public int Qty { get; set; }
        public decimal Price { get; set; }
        public DateTime EntryDate { get; set; }
    }
}

3.2. Tạo Context và kết nối đến cơ sở dữ liệu

  • Mở SQL sever và tạo 1 database LINQAspDemo:

  • Cài đặt nuget package Entity Framework vào project

  • Tạo thư mục Context trong project và tạo file ProductContext.cs để cấu hình context kết nối dữ liệu

Cấu hinh file ProductContext.cs như sau

using LINQAspDemo.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace LINQAspDemo.Context {
    public class ProductContext : DbContext{
        public DbSet<Product> Product { get; set; }
    }
}
<connectionStrings>
    <add name="ProductContext" connectionString="Data Source=DESKTOP-E2I8M9U\SQLEXPRESS;Initial Catalog=LINQAspDemo;Integrated Security=True" providerName="System.Data.SqlClient"/>
  </connectionStrings>

3.3. Tạo controller và View

  • Tạo controller ProductController.cs trong thư mục Controllers cấu hình như sau
using LINQAspDemo.Context;
using LINQAspDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace LINQAspDemo.Controllers
{
    public class ProductController : Controller
    {
        ProductContext db = new ProductContext(); //Tạo context kết nối đến cơ sở dữ liệu
        // GET: Product
        public ActionResult Index()
        {
            var Products = db.Product.ToList();
            return View(Products);
        }

        // GET: Product/Details/5
        public ActionResult Details(int id)
        {
            return View();
        }

        // GET: Product/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Product/Create
        [HttpPost]
        public ActionResult Create(FormCollection collection)
        {
            try
            {
                // TODO: Add insert logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        // GET: Product/Edit/5
        public ActionResult Edit(int id)
        {
            return View();
        }

        // POST: Product/Edit/5
        [HttpPost]
        public ActionResult Edit(int id, FormCollection collection)
        {
            try
            {
                // TODO: Add update logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        // GET: Product/Delete/5
        public ActionResult Delete(int id)
        {
            return View();
        }

        // POST: Product/Delete/5
        [HttpPost]
        public ActionResult Delete(int id, FormCollection collection)
        {
            try
            {
                // TODO: Add delete logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}

Tiến hảnh Rebuild Project, và click chuột phải vào vùng Action Index chọn add View:

Tương tự như thế add view cho Action Create

Cấu hình Action // POST: Product/Create:

Run app và tạo 1 vài dữ liệu tạm

3.4. Sử dụng LINQ để sắp xếp dữ liệu

Đầu tiên chỉnh sửa file index.html của view Product như sau:

Sau đó tạo Action OrderByName : Add view cho Action OrderByName:

Run App và sử dụng thử chức năng Order by name:

3.5. Giải thích ví dụ

Lấy một nguồn dữ liệu

Trong truy vấn LINQ, bước đầu tiên là đặc tả nguồn dữ liệu. Mệnh đề from phải có đầu tiên để mô tả nguồn dữ liệu (db.product) và biến phạm vi (p).

Biến phạm vi (range variable)

Giống như biến lặp trong vòng lặp foreach ngoại trừ không có vòng lặp nào xảy ra trong 1 diễn giải truy vấn. Khi truy vấn được thực thi, biến phạm vi sẽ đóng vai trò là 1 tham chiếu với mỗi phần tử tiếp theo trong db.product. Bởi vì trình biên dịch có thể suy luận dạng của 'p', vì vậy chúng ta không cần phải đặc tả kiểu dữ liệu cho 'p' rõ ràng.

Sắp xếp (order)

Mệnh đề orderby cho phép sắp xếp các phần tử theo thứ tự nào đó trong dữ liệu trả về.

- Một số mệnh đề mình không sử dụng trong ví dụ nhưng cũng rất hay dùng

Lọc dữ liệu (Filter)

Lọc dữ liệu là câu lệnh truy vấn phổ biến ở dạng diễn giải Boolean (đúng hoặc sai). Câu truy vấn chỉ trả về các phần tử nếu diễn giải là đúng (true). Để lọc dữ liệu, chúng ta dùng mệnh đề where, trong đó mô tả các điều kiện lọc.

Gom nhóm (group)

Mệnh đề group cho phép gom nhóm kết quả dựa trên 1 khóa được mô tả.

Kết hợp (join)

Tương tự như SQL, kết hợp (join) dữ liệu xảy ra giữa các tập đối tượng dữ liệu mà chưa được mô hình rõ ràng trong nguồn dữ liệu.

Chọn các trường dữ liệu (select)

Mệnh đề select dùng để chọn các dạng giá trị làm kết quả trả về trong 1 truy vấn LINQ.

4. Kết luận

Mình thấy LINQ giúp chúng ta xử lý các mảng dữ liệu lớn dù là Kiểu dữ liệu gì đi chăng nữa thì cũng rất nhanh và thuận tiện giúp code ngắn gọn, giảm thiểu được khá nhiều thao tác nghiệp vụ như vòng lặp, ép kiểu ..., dễ hiểu như ngôn ngữ thông thường, rất đáng để chúng ta học và tìm hiểu 👍

Cảm ơn các bạn đã theo dõi những chia sẻ khá dài dòng của mình 😅😆