How to make LINQ execute a (SQL) LIKE range search

后端 未结 3 1104
北恋
北恋 2020-12-06 23:29

I am in big need of help, i have been trying to do this for some time now.

So I have this Query:

Select name from BlaBlaBla

order by 

case when nam         


        
相关标签:
3条回答
  • 2020-12-06 23:39

    The problem here is that expressions containing Regex can't be translated to SQL, so even when you'd succeed in building a correct expression, you can't use it in LINQ to a SQL backend. However, SQL's LIKE method also supports range wildcards like [0-9], so the trick is to make your LINQ translate to SQL containing a LIKE statement.

    LINQ-to-SQL offers the possibility to use the SQL LIKE statement explicitly:

    return namesList.OrderBy(r => SqlMethods.Like(r.Name, "[0-9]%")) ...
    

    This SqlMethods class can only be used in LINQ-to-SQL though. In Entity Framework there are string functions that translate to LIKE implicitly, but none of them enable the range wildcard ([x-y]). In EF a statement like ...

    return namesList.OrderBy(r => r.Name.StartsWith("[0-9]")) ...
    

    ... would translate to nonsense:

    [Name] LIKE '~[0-9]%' ESCAPE '~'
    

    I.e. it vainly looks for names starting with the literal string "[0-9]". So as long as you keep using LINQ-to-SQL SqlMethods.Like is the way to go.

    In Entity Framework 6.1.3 (and lower) we have to use a slightly different way to obtain the same result ...

    return namesList.OrderBy(r => SqlFunctions.PatIndex("[0-9]%", c.Name) == 1) ...
    

    ... because PatIndex in SqlFunctions also supports range pattern matching.

    But in Entity Framwork 6.2 we're back on track with LINQ-to-SQL because of the new DbFunctions.Like function:

    return namesList.OrderBy(r => DbFunctions.Like(r.Name, "[0-9]%")) ...
    

    Finally, also Entity Framework core has a Like function:

    return namesList.OrderBy(r => EF.Functions.Like(r.Name, "[0-9]%")) ...
    
    0 讨论(0)
  • 2020-12-06 23:48

    Below you see a sample for this kind of way to handle cases for your orderings.

        static void Main(string[] args)
        {
            List<Obvious> list = new List<Obvious>();
            for (int i = 0; i < 100; i++)
            {
                list.Add(new Obvious(i.ToString(), i));
            }
    
            string name = list[30].name;
            switch (name)
            {
                case "9":
                    list.OrderBy(o => o.perc)
                        .ThenByDescending(o => o.name);
                    break;
                default:
                    list.OrderByDescending(o => o.name)
                        .ThenBy(o => o.perc);
                    break;
            }
        }
    
        public class Obvious
        {
            public string name { get; set; }
            public int perc { get; set; }
            public Obvious(string _name, int _perc)
            {
                this.name = _name;
                this.perc = _perc;
            }
    
        }
    
    0 讨论(0)
  • 2020-12-06 23:59

    If I was you I wouldn't try using Expressions to solve this issue since it brings in a lot of complexity.

    I see that you would like to have a generic method, so it can work with different domain entities, yet you are expecting that each entity has a Name property. You can solve this in a more simple way by defining interface that contains Name property. Like this:

        public static void Main()
        {
            var test = new List<YourDomainEntity>()
            {
                new YourDomainEntity() { Name = "1test", OtherProperty = "1"},
                new YourDomainEntity() { Name = "2test",  OtherProperty = "2" },
                new YourDomainEntity() { Name = "2test", OtherProperty = "1"   }
            };
    
            var k = Foo(test).ToList();
        }
    
        public interface INameOrderable
        {
            string Name { get; set; }
        }
    
        public interface IOtherPropertyOrderable
        {
            string OtherProperty { get; set; }
        }
    
        public static IEnumerable<T> Foo<T>(IEnumerable<T> list) where T : INameOrderable, IOtherPropertyOrderable
        {
            return list.OrderBy(a => a.Name, new NamesDescComparer()).ThenBy(b => b.OtherProperty);
        }
    
        public class NamesDescComparer : IComparer<string>
        {
            public int Compare(string x, string y) => -String.CompareOrdinal(x, y);
        }
    
        class YourDomainEntity : INameOrderable, IOtherPropertyOrderable
        {
            public string OtherProperty { get; set; }
            public string Name { get; set; }
        }
    

    I believe the method Foo is what you are looking for.

    Note the where T : INameOrderable part. It restricts usage of this method to entities that implement INameOrderable interface

    0 讨论(0)
提交回复
热议问题