Ответ 1
var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));
У меня есть текстовое поле, которое позволяет пользователю указать строку поиска, включая wild cards, например:
Joh*
*Johnson
*mit*
*ack*on
Прежде чем использовать LINQ to Entities, у меня была хранимая процедура, которая взяла эту строку в качестве параметра и сделала:
SELECT * FROM Table WHERE Name LIKE @searchTerm
И тогда я просто сделаю String.Replace('*', '%'), прежде чем передать его.
Теперь с LINQ to Entities я пытаюсь выполнить одно и то же. Я знаю, что есть StartsWith, EndsWith и Содержит поддержку, но она не будет поддерживать ее так, как мне нужно.
Я читал о "SqlMethods.Like" и пробовал это:
var people = from t in entities.People
where SqlMethods.Like(t.Name, searchTerm)
select new { t.Name };
Однако я получаю следующее исключение:
LINQ to Entities does not recognize the method 'Boolean Like(System.String,
System.String)' method, and this method cannot be translated into a store
expression.
Как получить эту же функциональность с помощью LINQ to Entities?
var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));
Как заставить его работать без проблем:
в вашей модели EDMX, добавьте:
<Function Name="String_Like" ReturnType="Edm.Boolean">
<Parameter Name="searchingIn" Type="Edm.String" />
<Parameter Name="lookingFor" Type="Edm.String" />
<DefiningExpression>
searchingIn LIKE lookingFor
</DefiningExpression>
</Function>
сразу после начатых разделов:
<edmx:ConceptualModels>
<Schema Namespace="Your.Namespace"...
Затем в любом месте вашего кода добавьте этот метод расширения:
//prior to EF 6 [System.Data.Objects.DataClasses.EdmFunction("Your.Namespace", "String_Like")]
//With EF 6
[System.Data.Entity.DbFunction("Your.Namespace", "String_Like")]
public static bool Like(this string input, string pattern)
{
/* Turn "off" all regular expression related syntax in
* the pattern string. */
pattern = Regex.Escape(pattern);
/* Replace the SQL LIKE wildcard metacharacters with the
* equivalent regular expression metacharacters. */
pattern = pattern.Replace("%", ".*?").Replace("_", ".");
/* The previous call to Regex.Escape actually turned off
* too many metacharacters, i.e. those which are recognized by
* both the regular expression engine and the SQL LIKE
* statement ([...] and [^...]). Those metacharacters have
* to be manually unescaped here. */
pattern = pattern.Replace(@"\[", "[").Replace(@"\]", "]").Replace(@"\^", "^");
return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
}
И там у вас есть.
Теперь вы можете сделать:
(from e in Entities
where e.Name like '%dfghj%'
select e)
или
string [] test = {"Sydney", "Melbourne", "adelaide", "ryde"};
test.Where(t=> t.Like("%yd%e%")).Dump();
Ну, ваши варианты:
Contains
. Я знаю, что вам это не нравится, но, возможно, это может быть сделано для работы.Вы можете сделать это:
using System.Data.Entity; // EntityFramework.dll v4.3
var queryResult=db.Accounts.AsQueryable().Where(x => x.Name.Contains(queryKey));
потому что Linq to Entity
не может преобразовать метод Contains()
в SQL, но Linq to SQL может это сделать. Я попытался найти метод, который может сделать приведение, наконец, AsQueryable()
, а также общую версию AsQueryable<T>()
. Я обнаружил, что могу сделать это, используя его таким образом в моем случае, но любой побочный эффект, который у меня есть, я не знаю, возможно, он потеряет некоторые функции в Entity
.
решение заключается в использовании SQLFunctions.PatIndex
var result = from c in items
where SqlFunctions.PatIndex(searchstring.ToLower(), c.fieldtoSearch) > 0
select c;
где 'searchstring' - это шаблон для поиска 'fieldtoSearch' - это поле для поиска
Patindex() поддерживает поиск с использованием поиска по строкам. Поиск нечувствителен к регистру.
var people = from t in entities.People
where t.Name.ToLower().Contains(searchTerm.ToLower())
select new { t.Name };
EDIT. Я могу смешивать синтаксис. Обычно я использую методы расширения; но содержит будет работать.
Вы даже можете добавить поддержку метода .Like() в LINQ to Entities, чтобы вместо предлагаемого (и рабочего)
var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));
просто
var people = entities.People.Where(p => p.Name.Like(searchTerm));
См. http://jendaperl.blogspot.com/2011/02/like-in-linq-to-entities.html
Вы можете делать все эти операторы с помощью LINQ как
string _search = "blow";
// joh* OR joh%
items.Where(i => i.Name.StartsWith(_search, StringComparison.OrdinalIgnoreCase));
// *son OR %son
items.Where(i => i.Name.EndsWith(_search, StringComparison.OrdinalIgnoreCase));
// *hns* OR %hns%
items.Where(i => i.Name.ToLower().Contains(_search));
Во время фильтрации вам не нужно использовать знак процента. например;
если я хочу проверить ItemName, не содержит '-', я сделаю это как
!Item.ItemName.Contains( "-" )
В SQL он преобразуется в NOT LIKE '% -%'
Мы используем Database First и EntityFramework.
"Составьте свою собственную функцию". подход работает для нас вместе с nuget EntityFramework.CodeFirstStoreFunctions.
1 Шаг: создайте функцию в db следующим образом:
CREATE FUNCTION [dbo].[StringLike]
(
@a nvarchar(4000),
@b nvarchar(4000)
)
RETURNS bit
AS
BEGIN
RETURN
(SELECT CASE
WHEN (SELECT 1 WHERE @a LIKE @b) = 1 THEN 1
ELSE 0
END)
END
2 Шаг: установите nuget EntityFramework.CodeFirstStoreFunctions
3 Шаг: создайте метод в вашем коде, как это (я создаю шахту в классе DbContext):
[DbFunction("CodeFirstDatabaseSchema", "StringLike")]
public static bool Like(string input, string pattern)
{
throw new NotSupportedException("Direct calls are not supported.");
}
4 Шаг: инициализировать EntityFramework.CodeFirstStoreFunctions.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType()));
}
5 Шаг: теперь вы можете использовать этот метод в своем запросе linq.