Làm thế nào để làm SQL Like% trong Linq?


385

Tôi có một quy trình trong SQL mà tôi đang cố gắng biến thành Linq:

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

Dòng tôi quan tâm nhất là:

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

Tôi có một cột lưu trữ thứ bậc như / 1/3/12 / chẳng hạn, vì vậy tôi chỉ sử dụng% / 12 /% để tìm kiếm nó.

Câu hỏi của tôi là, Linq hoặc .NET tương đương với việc sử dụng dấu phần trăm là gì?


1
Câu hỏi của bạn có ít nhất 5phiếu bầu cho thẻ nhà điều hành tương tự . Tôi có thể vui lòng yêu cầu bạn đề xuất như sql như một từ đồng nghĩa không?
Kermit

Câu trả lời:


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

Bạn cũng có thể sử dụng .StartsWith()hoặc .EndsWith().


4
Việc sử dụng StartsWith () hoặc EndsWith () sẽ thực hiện truy vấn? Ý tôi là, mã sẽ được dịch thành Truy vấn hay kết quả sẽ được lọc trong đối tượng sau khi truy xuất từ ​​DB?
Novice

5
Không. StartsWith () và EndsWith () là một phần của biến vị ngữ / bộ lọc. Thi hành tiếp tục được hoãn lại.
andleer

2
đã thử nhận NullReferenceException: Tham chiếu đối tượng không được đặt thành phiên bản của đối tượng. Vì vậy, nó không thích khi trong trường hợp của tôi a.Address1.StartsWith (Địa chỉ1) và a.Address1 là null
MikeT

11
StartsWith("abc")được chuyển đổi thành LIKE 'abc%'EndsWith("abc")được cnoverted đếnLIKE '%abc'
Simon_Weaver

20
Không thể tìm ra lý do tại sao điều này không hoạt động cho một trường hợp sử dụng với các chữ cái, sau đó nhận ra sự ngu ngốc của tôi ... đừng quên .ToLower().Contains()vv nếu bạn muốn bỏ qua trường hợp. Việc bạn muốn điều này tất nhiên sẽ phụ thuộc vào việc bạn có cố gắng bắt chước THÍCH từ DB với trường hợp đối chiếu không nhạy cảm hay không.
Hiệp sĩ Adam

251

Dùng cái này:

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

22
điều này thực sự hữu ích nếu bạn muốn sử dụng khớp mẫu phức tạp hơn được cung cấp bởi lệnh like. Chẳng hạn, nếu bạn muốn kiểm tra hai số bất kỳ (thay vì 12), bạn cũng có thể sử dụng biểu thức này: SqlMethods.Like (c.HVELy, "% / [0-9] [0-9] /%") , hãy xem msdn.microsoft.com/en-us/l
Library / aa933232 (SQL.80) .aspx

điều này cũng rất hữu ích nếu bạn muốn cho phép người dùng có quyền tự trả trước% ban đầu đắt đỏ, trong đó việc sử dụng StartsWith hoặc Contains không mang lại cho người dùng năng lượng sự linh hoạt này
Simon_Weaver

8
Làm thế nào để bạn sử dụng SqlMethodsbằng cách sử dụng "ký hiệu chấm"?
dan-gph

12
Lưu ý rằng bạn cần bao gồm System.Data.Linq.SqlClientkhông gian tên.
johna

1
Tôi không thể tìm thấy System.Data.Linq.SqlClient mặc dù tôi có thể thêm System.Data.Linq. Có bị phản đối không?
Burak Karakuş

41

Tôi giả sử bạn đang sử dụng Linq-to-SQL * (xem ghi chú bên dưới). Nếu vậy, hãy sử dụng string.Contains, string.StartsWith và string.EndsWith để tạo SQL sử dụng toán tử SQL THÍCH.

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 }

hoặc là

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

Lưu ý: * = nếu bạn đang sử dụng Khung thực thể ADO.Net (EF / L2E) trong .net 3.5, hãy lưu ý rằng nó sẽ không thực hiện bản dịch giống như Linq-to-SQL. Mặc dù L2S thực hiện một bản dịch phù hợp, L2E v1 (3.5) sẽ dịch thành biểu thức t-sql sẽ buộc quét toàn bộ bảng trên bảng mà bạn đang truy vấn trừ khi có một bộ phân biệt đối xử tốt hơn trong mệnh đề hoặc bộ lọc tham gia của bạn.
Cập nhật: Điều này được cố định trong EF / L2E v4 (.net 4.0), do đó, nó sẽ tạo ra một SQL THÍCH giống như L2S.


Không cần phải thoát khỏi chuỗi của bạn bằng @dấu hiệu nhưng tôi nhận ra đây có thể chỉ là một quy ước tốt để tuân theo.
andleer

27

Nếu bạn đang sử dụng VB.NET, thì câu trả lời sẽ là "*". Đây là mệnh đề where của bạn sẽ như thế nào ...

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

Lưu ý: "*" Khớp 0 hoặc nhiều ký tự. Đây là bài viết msDN cho toán tử Like .


Toán tử VB Like có dịch thành các cuộc gọi L2S không? (Tôi không có ý kiến ​​gì.)
andleer

8
Có, toán tử VB Like được dịch sang phiên bản SQL giống như khi được sử dụng trong biểu thức truy vấn LINQ. Ngoài ra, toán tử VB Like không bị hạn chế đối với các biểu thức truy vấn.
robertz

1
Tôi thấy rằng nó tồn tại bên ngoài các hoạt động LINQ. Đồ tốt. +1
andleer

9

IndexOf cũng hoạt động với tôi

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

1
Đây phải là câu trả lời được chấp nhận. IndexOf dịch sang CHARINDEX theo sql. Điều này có thể có thể nhanh hơn THÍCH. Nhưng ngoài ra, nó mang lại khả năng xây dựng các truy vấn tìm kiếm như '% some% thing%'. Trường hợp 'một số' phải được đặt trước 'điều', điều này không thể thực hiện được với Chứa.
Ruard van Elburg

Tôi thích nó khi câu trả lời tôi cần là 8 tuổi và giấu nhiều tầng bên dưới câu trả lời được chấp nhận. Nói một cách đơn giản, điều này hoạt động trong khi .Contains (@ "/ 12 /") và các câu trả lời tương tự khác thì không. Nhiều đánh giá cao!
IdusOrtus

4

Sử dụng mã như vậy

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;
}

4

Lõi .NET hiện có EF.Functions.Like


Bạn có thể giải thích cách sử dụng điều này để giải quyết vấn đề của OP không?
Robert Columbia

xem tức là câu trả lời từ LP, đây chỉ là phiên bản cốt lõi của SqlMethods. Giống như
kofifus

Câu trả lời này nên chứa một ví dụ hành động về cách sử dụng chức năng này.
FoxDeploy

3

Trong trường hợp bạn không khớp chuỗi số, luôn luôn có trường hợp phổ biến:

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

2

Tôi luôn luôn làm điều này:

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

Tôi biết tôi không sử dụng câu lệnh like nhưng nó hoạt động tốt trong nền là điều này được dịch thành truy vấn với câu lệnh like.


Câu trả lời của bạn khác với câu trả lời được chấp nhận (đã trả lời 7 năm trước) hoặc câu trả lời khác như thế nào? Nó có giá trị gì?
David Ferenczy Rogožan

1
@DawidFerenczy Câu trả lời này hoạt động với cú pháp truy vấn "from foo in bar", và câu hỏi được chấp nhận thì không.
mũi

1

Hãy thử nó, nó hoạt động tốt với tôi

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


0

Chứa được sử dụng trong Linq, Giống như Like được sử dụng trong SQL.

string _search="/12/";

. . .

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

Bạn có thể viết tập lệnh SQL của mình trong Linq như sau:

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

0

Đối với những người ở đây như tôi đang tìm cách chuyển sang phương thức "SQL Like" trong LINQ, tôi đã làm việc rất tốt.

Tôi đang ở trong trường hợp tôi không thể thay đổi Cơ sở dữ liệu theo bất kỳ cách nào để thay đổi đối chiếu cột. Vì vậy, tôi phải tìm một cách trong LINQ của mình để làm điều đó.

Tôi đang sử dụng phương thức SqlFunctions.PatIndexphù thủy phương thức trợ giúp hoạt động tương tự như toán tử SQL THÍCH thực sự.

Đầu tiên tôi cần liệt kê tất cả các dấu phụ có thể (một từ mà tôi vừa học) trong giá trị tìm kiếm để có được một cái gì đó như:

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

và sau đó trong LINQ cho ví dụ:

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();

Vì vậy, đối với nhu cầu của tôi, tôi đã viết một phương thức Trợ giúp / Gia hạn

   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;
        }
    }

Nếu bất kỳ ai trong số các bạn có đề xuất cải tiến phương pháp này, tôi sẽ vui lòng nghe bạn.


Ví dụ của bạn về cơ bản là một đối chiếu không nhạy cảm homebrewed homebrewed. Tôi đã từng phải đối phó với một dự án trong đó mỗi truy vấn đều đi qua một bộ lọc để đạt được điều mà một đối chiếu thích hợp sẽ tự động thực hiện. Vui lòng xem stackoverflow.com/a/2461550/1736944 để biết cách tiếp cận tốt hơn. Chỉ định đối chiếu thích hợp cho cơ sở dữ liệu, bảng và / hoặc trường nếu thấy phù hợp. (Làm việc mà không có sự đối chiếu thích hợp tại chỗ là cực hình)
9Rune5

0

Đã muộn, nhưng tôi đã kết hợp nó để có thể thực hiện so sánh Chuỗi bằng cách sử dụng các ký tự đại diện kiểu 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;
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.