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
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]%")) ...
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;
}
}
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