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ụ:
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:
Đố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.
Đầ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.