1

Say I have a table Table1 with a string field [ProductString] with values: Alpha, alphanumeric or numeric: eg ABC, B4, U2, C 5, 100, U1, U5, U6, U11

I want to be able to take a where clause like "ProductString >= U5", and pass this to a LINQ statement as a string so it evaluates

Table1.Where(t=> t.ProductString >= 'U5');

Normally this would return results U5 and U6.

However, this I want to be able to use a NaturalSortComparer somehow so that the results returned are U5, U6 and U11.

I know how to use the comparer in an OrderBy, by I wanted to be able to use it at the Where stage.

Andrew Roberts
  • 990
  • 2
  • 12
  • 26
  • Create an instance of the comparer then use it... – Jeff Mercado Sep 11 '14 at 07:21
  • @JeffMercado but predicate will be applied at server side. Whole table will be fetched and I think that the OP want follow this wayt. I'm afraid that stored procedure is necessary.. –  Sep 11 '14 at 07:24
  • @pwas: well it's unclear what the source is. If he had used that comparer in an earlier query, then it probably wasn't a database. We can guess all we want but in the end it won't matter until he clarifies. – Jeff Mercado Sep 11 '14 at 07:26
  • If this is a query executed by a database server, you can't. – CMircea Sep 11 '14 at 07:34
  • it's a query executed by a SQL Server database – Andrew Roberts Sep 11 '14 at 07:41
  • @AndrewRoberts, I'm curious... you say you know how to use the comparer in an `OrderBy`. Do you know if the `OrderBy` is being resolved to a SQL `order by` in the database, or is it being resolved in .NET after the data set is returned? – jdmcnair Sep 11 '14 at 22:12

3 Answers3

1

Using natural sort comparer:

var comparer = new NaturalComparer();
Table1.Where(t=> 
    comparer.Compare(t.ProductString, "U5") >= 0);

Presuming all your product strings is on the format U%number% then why not abuse that fact?

Table1.Where(t=> int.Parse(t.ProductString.Replace("U","")) >= 5);

If you're using LINQ to Entities I'm not certain this will compile to a store expression (i.e that SQL knows what to do with this - I guess it should).

AlexanderBrevig
  • 1,967
  • 12
  • 17
  • 2
    It will be covnerted into ExpressionTree, but EF will fail with translating it into SQL with `NotSupportedException`. –  Sep 11 '14 at 07:26
  • It cannot be assumed that the string is of this format. It may just be Alpha or alphanumeric or numeric: eg ABC, B4, U2, C 5, 100. I'll update the question – Andrew Roberts Sep 11 '14 at 07:32
  • would the solution using `NaturalComparer` fit your bill? – AlexanderBrevig Sep 11 '14 at 07:44
  • Would need to be this actually as LINQ to Entities does not know what the Compare method is: Table1.AsEnumerable() .Where(t => comparer.Compare(t.PriorityString, "U5") >= 0); – Andrew Roberts Sep 12 '14 at 05:32
  • The real query is a lot more generic than this: It is all user driven. ProductCode may not even be in the query depending on filters user chooses. And.. it's of an arbitrary format that is chosen by users. The query could be ((ProductCode > 'U5' Or Tag LIKE '%k') and Date < Now) Or (Message = 'text' And Date < yesterday) OR SomeOtherString = '100' or Priority <= '100X'. – Andrew Roberts Sep 12 '14 at 05:43
  • posted another question https://stackoverflow.com/questions/25802467/dynamic-linq-where-clause-as-string-using-naturalcomparer to reflect this – Andrew Roberts Sep 12 '14 at 07:28
1

I'm a little confused, given the accepted answer, about whether this question relates to LINQ to Entities or not. The accepted answer doesn't appear to be a solution that would work in the LINQ to Entities context, but the comments on the question by the OP seem to confirm that this is being executed in the database context. Anyway, this answer is specifically targeted toward LINQ to Entities.

I think doing this in SQL Server would be hard, but not impossible. The problem is that .NET knows what NaturalSortComparer is, but SQL Server (where you want the query to ultimately take place) has no such concept. The best idea I can think of would consist of 2 parts:

  1. Create a UDF (User Defined Function) in SQL server that will give a product that is orderable via natural sort: CREATE FUNCTION Naturalize(@val as nvarchar(max)) RETURNS nvarchar(1000). There's a pretty cool answer here that creates a UDF wrapper around a CLR function to accomplish just that.
  2. Next create a function mapping for your DbContext that maps the UDF above to a function that can be called inside an EF query against the DbContext. Something like this:

    [DbFunction("MyContext", "Naturalize")]
    public static string Naturalize(this string value)
    {
        throw new NotSupportedException("This function can only be invoked from LINQ to Entities.");
    }
    

Once you've got these two pieces in place, you can readily use this new function inside an entity query to compare strings using the Naturalized value in the comparison:

Table1.Where(t=> t.ProductString.Naturalize() >= "U5".Naturalize());

Bear in mind that the UDF will be executed against every row contained in the query, which is the whole table in the above example. You'll want to make sure to pare down your query to something manageable before applying the function as a sub-query. Or you may want to try applying some type of UDF-based index on the table in question.

Community
  • 1
  • 1
jdmcnair
  • 1,305
  • 15
  • 33
0

If you are going to be doing searches like this a lot, then what will be the best thing to do is add two new fields to your table, [ProductCode] & [ProductNumber] which separate the two parts of the [ProductString].

Then you comparison becomes:

 Table1.Where(t=> t.ProductCode == "U" && t.ProductNumer > 5);
James Curran
  • 101,701
  • 37
  • 181
  • 258