C# Linq 中的 SQL LIKE

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17081065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:31:48  来源:igfitidea点击:

SQL LIKE in Linq

c#.netlinqtsqlsql-to-linq-conversion

提问by Sai

Before adding this question, I did search on stackoverflow for similar ones but I couldnt find. Most of the questions over internet were using LIKE with a string (for eg LIKE '%ABC%') but I need to compare with an existing column of a different table.

在添加这个问题之前,我确实在 stackoverflow 上搜索过类似的问题,但我找不到。互联网上的大多数问题都使用带有字符串的 LIKE(例如 LIKE '%ABC%'),但我需要与不同表的现有列进行比较。

I need to write a linq query for the select statement as below -

我需要为 select 语句编写一个 linq 查询,如下所示 -

 select * 
from [dbo].[BaseClaim]
where WPId like (select WPId from UserProfiles where ID='1459') 

I came up with below linq query but its not working as expected -

我想出了以下 linq 查询,但没有按预期工作 -

     var result = (from claimsRow in context.BaseClaims
                          where (from upRow in context.UserProfiles
                                 where upRow.ID == 1459
                                 select upRow.WPId).Contains(claimsRow.WPId)
                          select claimsRow);

and the sql that above linq generates is as follows -

而上面linq生成的sql如下——

   SELECT 
   [Extent1].[WPId] AS [WPId]
   FROM [dbo].[BaseClaim] AS [Extent1]
   WHERE  EXISTS (SELECT 
             1 AS [C1]
                 FROM (SELECT 
                       [UserProfiles].[ID] AS [ID], 
                       [UserProfiles].[WPId] AS [WPId]      
                       FROM [dbo].[UserProfiles] AS [UserProfiles]) AS [Extent2]
                   WHERE (1459 = [Extent2].[ID]) AND ([Extent2].[WPId] = [Extent1].[WPId]))

So its clear that my linq is not working as its comparing the baseclaim.wpID to userprofiles.wpid instead of LIKE.

所以很明显,我的 linq 无法正常工作,因为它将 baseclaim.wpID 与 userprofiles.wpid 进行比较而不是 LIKE。

采纳答案by p.s.w.g

There's no direct equivalent, but there are some methods work similarly, depending on the pattern.

没有直接的等价物,但有一些方法的工作方式类似,具体取决于模式。

  • string.Contains("pattern")is equivalent to LIKE '%pattern%'
  • string.StartsWith("pattern")is equivalent to LIKE 'pattern%'
  • string.EndsWith("pattern")is equivalent to LIKE '%pattern'
  • string.Contains("pattern")相当于 LIKE '%pattern%'
  • string.StartsWith("pattern")相当于 LIKE 'pattern%'
  • string.EndsWith("pattern")相当于 LIKE '%pattern'

However, in your SQL query the pattern is dynamic, so I don't think there is a good way to convert it straight to Linq. If you know at design time that the pattern fits one of these cases you can use this:

但是,在您的 SQL 查询中,模式是动态的,因此我认为没有将其直接转换为 Linq 的好方法。如果您在设计时知道该模式适合这些情况之一,您可以使用它:

var result =
    from claimsRow in context.BaseClaims
    let wpId = context.UserProfiles.Single(upRow => upRow.ID == 1459).WPId
    where claimsRow.WPId.Contains(wpId) // or StartsWith or EndsWith
    select claimsRow;

Or possibly

或者可能

var wpId =
    (from upRow in context.UserProfiles
     where upRow.ID == 1459
     select upRow.WPId)
    .Single();
var result =
    from claimsRow in context.BaseClaims
    where claimsRow.WPId.Contains(wpId) // or StartsWith or EndsWith
    select claimsRow;

回答by Microtechie

You must use contain for example

例如,您必须使用包含

 .Where(a => a.Name.Contains("someStrig")

Contains generate Like when the parameter is constant

参数为常量时包含 generate Like

Hope it helps

希望能帮助到你

回答by Sergey Berezovskiy

This query works with Entity Framework

此查询适用于实体框架

from claimsRow in context.BaseClaims
let wpId = context.UserProfiles.Where(upRow => upRow.ID == 1459) 
                               .Select(upRow => upRow.WPId)
                               .FirstOrDefault() 
where wpId.Contains(claimsRow.WPId)
select claimsRow

But instead of LIKEit generates CHARINDEXoperation

但不是LIKE它生成CHARINDEX操作

SELECT * FROM  [dbo].[BaseClaims] AS [Extent1]
LEFT OUTER JOIN  (SELECT TOP (1) [Extent2].[WPId] AS [WPId]
                  FROM [dbo].[UserProfiles] AS [Extent2]
                  WHERE [Extent2].[ID] = 1459 ) AS [Limit1] ON 1 = 1
WHERE (CHARINDEX([Extent1].[WPId], [Limit1].[WPId])) > 0

Note: with Linq to SQL it throws NotSupportedException:

注意:使用 Linq to SQL 它会抛出 NotSupportedException:

Only arguments that can be evaluated on the client are supported for the String.Contains method.

String.Contains 方法仅支持可以在客户端上计算的参数。

回答by aiapatag

EDITED:

编辑:

The asker said that he has wild cards (%) in his UserProfile.WPId that should work like the wildcards in SQL.

提问者说%他的 UserProfile.WPId 中有通配符 ( ),应该像 SQL 中的通配符一样工作。

You can use this one:

你可以使用这个:

BaseClaims.Where(b => UserProfiles.Where(u => u.ID == "1459").Any(u => u.WPId.Contains(b.WPId))).ToList();

BaseClaims.Where(b => UserProfiles.Where(u => u.ID == "1459").Any(u => u.WPId.Contains(b.WPId))).ToList();

In this example, I'm trying to mimic your entities/tables.

在这个例子中,我试图模仿你的实体/表。

    static void Main(string[] args)
    {
        List<BaseClaim> BaseClaims = new List<BaseClaim>()
        {
            new BaseClaim(){ WPId = "11123411" }, //match 1
            new BaseClaim(){ WPId = "11123123" }, //match 2
            new BaseClaim(){ WPId = "44423411" }, //match 3
            new BaseClaim(){ WPId = "444AAAA" }, //match 3
            new BaseClaim(){ WPId = "444BBBB" }, //match 3
            new BaseClaim(){ WPId = "444QWQEQW" }, //match 3
            new BaseClaim(){ WPId = "2314" },
            new BaseClaim(){ WPId = "3214" }
        };
        List<UserProfile> UserProfiles = new List<UserProfile>()
        { 
            new UserProfile(){ WPId="%112341%", ID="1459" }, //match 1
            new UserProfile(){ WPId="%123", ID="1459" }, //match 2
            new UserProfile(){ WPId="444%", ID="1459" }, //match 3
            new UserProfile(){ WPId="5555", ID="1459" },
            new UserProfile(){ WPId="2222", ID="1459" },
            new UserProfile(){ WPId="1111", ID="4444" },
        };

        char[] asterisk = { '%' };
        List<BaseClaim> result = BaseClaims.Where(b => UserProfiles.Where(u => u.ID == "1459").Any(u => u.WPId.StartsWith("%") && u.WPId.EndsWith("%") ? b.WPId.Contains(u.WPId.Trim(asterisk)) :
                                                                                                        u.WPId.StartsWith("%") ? b.WPId.EndsWith(u.WPId.Trim(asterisk)) : 
                                                                                                        u.WPId.EndsWith("%") ? b.WPId.StartsWith(u.WPId.Trim(asterisk)) :
                                                                                                         false)).ToList();
        //this will result to getting the first 3 BaseClaims

    }