如何在Linq中执行SQL Like%?


385

我有一个试图转换为Linq的SQL过程:

SELECT O.Id, O.Name as Organization
FROM Organizations O
JOIN OrganizationsHierarchy OH ON O.Id=OH.OrganizationsId
where OH.Hierarchy like '%/12/%'

我最关心的行是:

where OH.Hierarchy like '%/12/%'

我有一列存储例如/ 1/3/12 /之类的层次结构,因此我只使用%/ 12 /%进行搜索。

我的问题是,Linq或.NET与使用百分号等效吗?


1
您的问题至少5like-operator标签具有投票权。我可以请您建议像sql这样同义词吗?
Kermit

Answers:


550
.Where(oh => oh.Hierarchy.Contains("/12/"))

您也可以使用.StartsWith().EndsWith()


4
使用StartsWith()或EndsWith()是否会触发查询?我的意思是,将代码从数据库中检索后转换为查询还是将结果过滤到对象中?
新手2012年

5
不会。StartsWith()和EndsWith()是谓词/过滤器的一部分。执行继续被推迟。
andleer 2012年

2
尝试得到NullReferenceException:对象引用未设置为对象的实例。因此,在我的情况下,a.Address1.StartsWith(Address1)和a.Address1为空时,它不喜欢它
MikeT 2013年

11
StartsWith("abc")被转换成LIKE 'abc%'EndsWith("abc")被cnoverted到LIKE '%abc'
Simon_Weaver

20
无法弄清楚为什么它不适用于带字母的用例,然后意识到我的愚蠢…… .ToLower().Contains()如果您想忽略大小写,请不要忘记等。是否要这样做当然取决于您是否尝试从不区分大小写的排序规则中模仿数据库中的LIKE。
亚当·

251

用这个:

from c in dc.Organization
where SqlMethods.Like(c.Hierarchy, "%/12/%")
select *;

22
如果您想使用like命令提供的更复杂的模式匹配,这将非常有用。例如,如果要检查任何两个数字(而不是12),则可以使用以下表达式:SqlMethods.Like(c.Hierarchy,“%/ [0-9] [0-9] /%”) ,请参见msdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity 2010年

如果您想允许高级用户自己在昂贵的初始%之前添加费用,这也非常有用,因为使用StartsWith或Contains不会给高级用户带来这种灵活性
Simon_Weaver

8
您如何SqlMethods使用“点符号”?
dan-gph 2014年

12
请注意,您需要包括System.Data.Linq.SqlClient名称空间。
约翰娜

1
尽管可以添加System.Data.Linq,但找不到System.Data.Linq.SqlClient。是否已弃用?
BurakKarakuş2015年

41

我假设您正在使用Linq-to-SQL *(请参阅下面的注释)。如果是这样,请使用string.Contains,string.StartsWith和string.EndsWith生成使用SQL LIKE运算符的SQL。

from o in dc.Organization
join oh in dc.OrganizationsHierarchy on o.Id equals oh.OrganizationsId
where oh.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

要么

from o in dc.Organization
where o.OrganizationsHierarchy.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

注意: * =如果在.net 3.5中使用ADO.Net实体框架(EF / L2E),请注意它将不会执行与Linq-to-SQL相同的转换。尽管L2S进行了适当的转换,但L2E v1(3.5)会转换为t-sql表达式,该表达式将强制对您查询的表进行全表扫描,除非where子句或联接过滤器中有另一个更好的区分符。
更新:这已在EF / L2E v4(.net 4.0)中修复,因此它将像L2S一样生成SQL LIKE。


无需用@符号来转义您的字符串,但我意识到这可能只是遵循的一个好习惯。
andleer 2013年

27

如果您使用的是VB.NET,则答案为“ *”。这是您的where子句的样子……

Where OH.Hierarchy Like '*/12/*'

注意:“ *”匹配零个或多个字符。这是Like运算符的msdn文章


VB Like运算符可以转换为L2S呼叫吗?(我不知道。)
andleer

8
是的,在LINQ查询表达式中使用时,VB Like运算符会转换为like的SQL版本。同样,VB Like运算符不限于查询表达式。
罗伯茨2009年

1
我看到它存在于LINQ操作之外。好东西。+1
andleer

9

好吧indexOf也对我有用

var result = from c in SampleList
where c.LongName.IndexOf(SearchQuery) >= 0
select c;

1
这应该是公认的答案。IndexOf在sql中转换为CHARINDEX。这可能比LIKE快。但除此之外,它还可以构造“%some%thing%”之类的搜索查询。必须在“事物”之前放置“某些”的位置,而“包含”是无法做到的。
Ruard van Elburg

当我需要的答案已经8岁并且被接受的答案掩盖了几层时,我会喜欢它。简而言之,这有效,而.Contains(@“ / 12 /”)和其他类似的答案却没有。非常感激!
IdusOrtus

4

使用这样的代码

try
{
    using (DatosDataContext dtc = new DatosDataContext())
    {
        var query = from pe in dtc.Personal_Hgo
                    where SqlMethods.Like(pe.nombre, "%" + txtNombre.Text + "%")
                    select new
                    {
                        pe.numero
                        ,
                        pe.nombre
                    };
        dgvDatos.DataSource = query.ToList();
    }
}
catch (Exception ex)
{
    string mensaje = ex.Message;
}


3

如果您不匹配数字字符串,通常情况下总是很好:

.Where(oh => oh.Hierarchy.ToUpper().Contains(mySearchString.ToUpper()))

2

我总是这样做:

from h in OH
where h.Hierarchy.Contains("/12/")
select h

我知道我不使用like语句,但是在后台将它翻译成带有like语句的查询是可行的。


您的答案与接受的答案(7年前回答)或其他答案有何不同?它增加了什么价值?
David FerenczyRogožan2016年

1
@DawidFerenczy此答案适用于“ from foo in bar”查询语法,但接受的语法无效。
nasch

1

试试这个,对我来说很好

from record in context.Organization where record.Hierarchy.Contains(12) select record;


0

在Linq中使用Contains,就像在SQL中使用Like一样

string _search="/12/";

。。。

.Where(s => s.Hierarchy.Contains(_search))

您可以在Linq中编写SQL脚本,如下所示:

 var result= Organizations.Join(OrganizationsHierarchy.Where(s=>s.Hierarchy.Contains("/12/")),s=>s.Id,s=>s.OrganizationsId,(org,orgH)=>new {org,orgH});

0

对于那些像我这样在寻找如何在LINQ中实现“ SQL Like”方法的人来说,我的工作非常好。

我无法以任何方式更改数据库来更改列排序规则。因此,我必须在LINQ中找到一种方法来做到这一点。

我使用的辅助方法SqlFunctions.PatIndex类似于实际的SQL LIKE运算符。

首先,我需要在搜索值中列举所有可能的变音符号(我刚刚学到的一个单词),以获得类似以下内容:

déjà     => d[éèêëeÉÈÊËE]j[aàâäAÀÂÄ]
montreal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l
montréal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l

然后以LINQ为例:

var city = "montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l";
var data = (from loc in _context.Locations
                     where SqlFunctions.PatIndex(city, loc.City) > 0
                     select loc.City).ToList();

因此,为了我的需要,我编写了一个Helper / Extension方法

   public static class SqlServerHelper
    {

        private static readonly List<KeyValuePair<string, string>> Diacritics = new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>("A", "aàâäAÀÂÄ"),
            new KeyValuePair<string, string>("E", "éèêëeÉÈÊËE"),
            new KeyValuePair<string, string>("U", "uûüùUÛÜÙ"),
            new KeyValuePair<string, string>("C", "cçCÇ"),
            new KeyValuePair<string, string>("I", "iîïIÎÏ"),
            new KeyValuePair<string, string>("O", "ôöÔÖ"),
            new KeyValuePair<string, string>("Y", "YŸÝýyÿ")
        };

        public static string EnumarateDiacritics(this string stringToDiatritics)
        {
            if (string.IsNullOrEmpty(stringToDiatritics.Trim()))
                return stringToDiatritics;

            var diacriticChecked = string.Empty;

            foreach (var c in stringToDiatritics.ToCharArray())
            {
                var diac = Diacritics.FirstOrDefault(o => o.Value.ToCharArray().Contains(c));
                if (string.IsNullOrEmpty(diac.Key))
                    continue;

                //Prevent from doing same letter/Diacritic more than one time
                if (diacriticChecked.Contains(diac.Key))
                    continue;

                diacriticChecked += diac.Key;

                stringToDiatritics = stringToDiatritics.Replace(c.ToString(), "[" + diac.Value + "]");
            }

            stringToDiatritics = "%" + stringToDiatritics + "%";
            return stringToDiatritics;
        }
    }

如果您有任何建议要改进此方法,请您多多包涵。


您的示例基本上是自制的重音不敏感排序规则。我曾经不得不处理一个项目,在该项目中,每个查询都要经过一个过滤器,以实现适当的整理会自动完成的工作。请访问stackoverflow.com/a/2461550/1736944了解通常哪种更好的方法。将适当的排序规则分配给认为合适的数据库,表和/或字段。(没有适当的校对工作就是纯粹的酷刑)
9Rune5 '19

0

太晚了,但是我将其结合在一起,以便能够使用SQL Like样式通配符进行字符串比较:

public static class StringLikeExtensions
{
    /// <summary>
    /// Tests a string to be Like another string containing SQL Like style wildcards
    /// </summary>
    /// <param name="value">string to be searched</param>
    /// <param name="searchString">the search string containing wildcards</param>
    /// <returns>value.Like(searchString)</returns>
    /// <example>value.Like("a")</example>
    /// <example>value.Like("a%")</example>
    /// <example>value.Like("%b")</example>
    /// <example>value.Like("a%b")</example>
    /// <example>value.Like("a%b%c")</example>
    /// <remarks>base author -- Ruard van Elburg from StackOverflow, modifications by dvn</remarks>
    /// <remarks>converted to a String extension by sja</remarks>
    /// <seealso cref="/programming/1040380/wildcard-search-for-linq"/>
    public static bool Like(this String value, string searchString)
    {
        bool result = false;

        var likeParts = searchString.Split(new char[] { '%' });

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = value.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = value.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= value.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = value.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = value.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }

    /// <summary>
    /// Tests a string containing SQL Like style wildcards to be ReverseLike another string 
    /// </summary>
    /// <param name="value">search string containing wildcards</param>
    /// <param name="compareString">string to be compared</param>
    /// <returns>value.ReverseLike(compareString)</returns>
    /// <example>value.ReverseLike("a")</example>
    /// <example>value.ReverseLike("abc")</example>
    /// <example>value.ReverseLike("ab")</example>
    /// <example>value.ReverseLike("axb")</example>
    /// <example>value.ReverseLike("axbyc")</example>
    /// <remarks>reversed logic of Like String extension</remarks>
    public static bool ReverseLike(this String value, string compareString)
    {
        bool result = false;

        var likeParts = value.Split(new char[] {'%'});

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = compareString.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = compareString.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= compareString.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = compareString.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = compareString.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.