Tìm kiếm kí tự không dấu trong LinQ Entity Framework Lập trình ASP.NET


Các bạn vẫn thường sử dụng  LinQ với Entity Framework để tìm kiếm ký tự và chuỗi, nhưng có một vấn đề là khi các bạn tìm từ khoá không dấu để ra có dấu thì không được. Mình xin đưa ra một số giải pháp.

Đầu tiên khi chúng ta muốn tìm kiếm chữ "đào tạo" trong CSDL thì rất đơn giản chúng ta chỉ cần sử dụng LinQ bằng mệnh đề where ví dụ:

var query = db.Categories.Where(c=>c.Name.Contains(keyword));

Nhưng khi chúng ta muốn người dùng chỉ cần gõ chữ "dao tao" thì phải ra được kết quả có chữ "đào tạo" như ý muốn thì lại không được. Ở đây chúng ta có 1 số giải pháp như sau:

Cách thứ nhất: Set collation cho cột trên bảng cần tìm kiếm là "SQL_Latin1_General_CP1_CI_AI"

Cách thứ hai: Chúng ta sử dụng delegate trong mệnh đề where, trong delegate sẽ sử dụng hàm chuyển đổi tiếng Việt sang chữ không dấu rồi so sánh:

Đầu tiên chúng ta có mệnh đề where như sau:

var query = db.Categories.Where(delegate (Category c)
                {
                    if (ConvertToUnSign(c.Name).IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0)
                        return true;
                    else
                        return false;
                }).AsQueryable();

Hàm ConvertToUnsign chúng ta có nội dung như sau:

private string ConvertToUnSign(string input)
        {
            input = input.Trim();
            for (int i = 0x20; i < 0x30; i++)
            {
                input = input.Replace(((char)i).ToString(), " ");
            }
            Regex regex = new Regex(@"\p{IsCombiningDiacriticalMarks}+");
            string str = input.Normalize(NormalizationForm.FormD);
            string str2 = regex.Replace(str, string.Empty).Replace('đ', 'd').Replace('Đ', 'D');
            while (str2.IndexOf("?") >= 0)
            {
                str2 = str2.Remove(str2.IndexOf("?"), 1);
            }
            return str2;
        }

Cách thứ ba: Chúng ta tạo sẵn trường dữ liệu không dấu tương ứng với cột dữ liệu để tìm kiếm dạng OR:

var query = db.Categories.Where(c=>c.Name.Contains(keyword) || c.NameUnsigned.Contains(keyword));

Kết luận:

Đối với 3 cách này thì mình thích dùng cách thứ 2 nhất vì nó tiện lợi, chúng ta không can thiệp trực tiếp vào DB như cách 1 và cũng không cần phải lưu dư thừa dữ liệu như cách 3 nhưng tốc độ đương nhiên không nhanh như cách 1 và 3 vì mỗi lần tìm kiếm lại phải chuyển đổi. Các bạn có thể cân nhắc 1 trong 3 cách để chúng ta vận dụng phù hợp nhất theo từng dự án.