如何在LINQ to Entities中使用SQL'LIKE'?

时间:2010-06-22 18:04:33

标签: c# sql linq-to-entities

我有一个文本框,允许用户指定搜索字符串,包括通配符,例如:

Joh*
*Johnson
*mit*
*ack*on

在使用LINQ to Entities之前,我有一个存储过程,它将该字符串作为参数并执行:

SELECT * FROM Table WHERE Name LIKE @searchTerm

然后我会在传入之前执行String.Replace('*','%')。

现在有了LINQ to Entities,我正在尝试完成同样的事情。我知道有StartsWith,EndsWith和Contains支持,但它不会以我需要的方式支持它。

我读到了“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获得相同的功能?

11 个答案:

答案 0 :(得分:34)

http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/6529a35b-6629-44fb-8ea4-3a44d232d6b9/

var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));

答案 1 :(得分:12)

如何让它无缝地工作:

在您的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();

答案 2 :(得分:8)

嗯,您的选择是:

  • 使用Contains。我知道你不喜欢它,但它可能会起作用。
  • SqlFunctions中选择一项功能。它们都得到了L2E的支持。
  • Map your own function
  • +1给ESQL的@Yury。

答案 3 :(得分:3)

你可以这样做:

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丢失一些功能。

答案 4 :(得分:2)

解决方案是使用SQLFunctions.PatIndex

var result = from c in items
             where SqlFunctions.PatIndex(searchstring.ToLower(), c.fieldtoSearch) > 0
             select c;

其中'searchstring'是要搜索的模式       'fieldtoSearch'是要搜索的字段

Patindex()支持使用字符串模式搜索进行搜索。搜索不区分大小写。

答案 5 :(得分:1)

您可以像这样使用LINQ执行所有这些语句

string _search = "johnson";
// 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));

答案 6 :(得分:1)

现在,EF支持“ LIKE”用法,您可以使用所有sql通配符。检查一下。

var people = from t in entities.People
             select new { t.Name };
people = people.Where(x => DbFunctions.Like(x.Name, searchTerm));

答案 7 :(得分:0)

var people = from t in entities.People
                 where t.Name.ToLower().Contains(searchTerm.ToLower())
                 select new { t.Name };
编辑 - 我可能会混合语法。我通常使用扩展方法;但是包含会起作用。

答案 8 :(得分:0)

过滤时不需要使用百分号。 e.g;

如果我想检查ItemName不包含&#39; - &#39;我会这样做

Item.ItemName.Contains(&#34; - &#34)

在SQL中,它将转换为NOT LIKE&#39;% - %&#39;

答案 9 :(得分:0)

我们使用Database First和EntityFramework。

&#34;映射您自己的功能。&#34;方法与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查询中使用此方法。

答案 10 :(得分:0)

可以通过以下方法轻松实现

var people = from t in entities.People
             where t.Name.Contains(searchTerm)
             select new { t.Name };

使用以下规范获取通配符

LIKE 'a%' => StartsWith("a")
LIKE '%a' => EndsWith("a")
LIKE '%a%' => Contains("a")
LIKE 'a%b' => StartsWith("a") && EndsWith("b")
LIKE '%a%b%' => StartsWith("a") && Contains("b")