Nhìn vào câu hỏi
gì nếu tôi muốn một cái gì đó như% Kiểm tra xem nó hoạt động%%, làm thế nào để làm điều đó?
sau đó tôi đang mong đợi một cái gì đó của
LIKE '%Test if%it work%'
nghĩa là chuỗi phải chứa 'Kiểm tra xem' và 'nó hoạt động', theo thứ tự mà.
này sẽ không làm việc:
context.SomeTable.Where(s => s.Name.Contains("Test if%it work")).ToList();
Và nếu tôi sử dụng:
context.SomeTable.Where(s => s.Name.Contains("Test if") && s.Name.Contains("it work")).ToList();
sau đó tôi sẽ tìm thấy tất cả hồ sơ có chứa cả hai "Kiểm tra xem" và "nó hoạt động", nhưng không cụ thể theo thứ tự đó.
Vì vậy, với Chứa điều này là không thể. Nhưng với IndexOf.
IndexOf sẽ tìm chuỗi tìm kiếm VÀ trả về vị trí của chuỗi đó trong chuỗi. Làm cho nó có thể tìm thấy những từ theo đúng thứ tự.
- Cập nhật -
Với câu trả lời ban đầu của tôi đó không phải là mục tiêu của tôi để cung cấp một giải pháp chung chung, mà là một ví dụ về cách tiếp cận khác mà không phải là sql dependend. Vì vậy, chính xác là ví dụ ban đầu chỉ trả lời câu hỏi theo nghĩa đen. Nhưng kể từ khi câu trả lời có thể hữu ích hơn nếu nó là chung chung, tôi đã viết một phần mở rộng IQuerable cho phép thêm một tuyên bố giống như truy vấn dễ dàng như là một tuyên bố nơi. Phần mở rộng hoạt động cho cả Linq như Linq-Sql.
Thao tác này sẽ tìm tất cả các bản ghi có cả "Kiểm tra nếu" và "nó hoạt động", theo thứ tự đó.
context.SomeTable.Like("test if%it work", "Name").ToList();
listOfString.Like("test if%it work").ToList();
mở rộng, cho phép bất kỳ số lượng các kí hiệu:
/// <summary>
/// Allow to search the string with wildcards.
/// </summary>
/// <typeparam name="T">String or an object with a string member.</typeparam>
/// <param name="q">Original query</param>
/// <param name="searchstring">The searchstring</param>
/// <param name="memberName">The name of the field or null if not a field.</param>
/// <returns>Query filtered by 'LIKE'.</returns>
public static IQueryable<T> Like<T>(this IQueryable<T> q, string searchstring, string memberName = null)
{
// %a%b%c% --> IndexOf(a) > -1 && IndexOf(b) > IndexOf(a) && IndexOf(c) > IndexOf(b)
var eParam = Expression.Parameter(typeof(T), "e");
MethodInfo methodInfo;
// Linq (C#) is case sensitive, but sql isn't. Use StringComparison ignorecase for Linq.
// Sql however doesn't know StringComparison, so try to determine the provider.
var isLinq = (q.Provider.GetType().IsGenericType && q.Provider.GetType().GetGenericTypeDefinition() == typeof(EnumerableQuery<>));
if (isLinq)
methodInfo = typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) });
else
methodInfo = typeof(string).GetMethod("IndexOf", new[] { typeof(string) });
Expression expr;
if (string.IsNullOrEmpty(memberName))
expr = eParam;
else
expr = Expression.Property(eParam, memberName);
// Split the searchstring by the wildcard symbol:
var likeParts = searchstring.Split(new char[] { '%' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < likeParts.Length; i++)
{
MethodCallExpression e;
if (isLinq)
e = Expression.Call(expr, methodInfo, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) });
else
e = Expression.Call(expr, methodInfo, Expression.Constant(likeParts[i], typeof(string)));
if (i == 0)
{
// e.IndexOf("likePart") > -1
q = q.Where(Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(e, Expression.Constant(-1, typeof(int))), eParam));
}
else
{
// e.IndexOf("likePart_previous")
MethodCallExpression ePrevious;
if (isLinq)
ePrevious = Expression.Call(expr, methodInfo, new Expression[] { Expression.Constant(likeParts[i - 1], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) });
else
ePrevious = Expression.Call(expr, methodInfo, Expression.Constant(likeParts[i - 1], typeof(string)));
// e.IndexOf("likePart_previous") < e.IndexOf("likePart")
q = q.Where(Expression.Lambda<Func<T, bool>>(Expression.LessThan(ePrevious, e), eParam));
}
}
return q;
}
Kể từ khi nó không cần SqlMethods Tôi giả sử bạn có thể sử dụng này cho bất kỳ cơ sở dữ liệu, như MySQL hoặc PostgreSQL. Nhưng tôi không biết chắc chắn. Tôi đã kiểm tra điều này với Sql Server bằng Entity Framework 6. Câu lệnh trên tạo ra đoạn mã sau trong Sql Server.
SELECT [Extent1].* FROM SomeTable AS [Extent1]
WHERE (((CAST(CHARINDEX(N'test if', [Extent1].[Name]) AS int)) - 1) > -1)
AND (((CAST(CHARINDEX(N'test if', [Extent1].[Name]) AS int)) - 1) <
((CAST(CHARINDEX(N'it work', [Extent1].[Name]) AS int)) - 1))
Giới thiệu về hiệu suất, có vẻ như có một số cuộc thảo luận về 'tốt hơn': LIKE hoặc CHARINDEX.Và từ những gì tôi đã đọc, CHARINDEX dường như được yêu thích.
Bit dài quanh co - ông chỉ có thể sử dụng SqlMethods.Like –
Bạn luôn luôn giả định rằng bạn đang gọi một cơ sở dữ liệu SQL. Điều gì xảy ra nếu bạn truy vấn danh sách được tạo trong bộ nhớ? –
Câu hỏi của ông được gắn thẻ với SQL –