9
public static void MyFunction(MyErrorClass err)
{
    var query = from filter in DataContext.ErrorFilters select filter;
    query = query.Where(f => err.ErrorMessage.Contains(f.ErrorMessage));
    List<ErrorFilter> filters = query.ToList();
    //...more code
}

So I'm having some issues with the above code, and I'm getting the error from the subject line at the line with query.ToList(). Here's what I'm trying to do:

First off, I have a custom error class, MyErrorClass. Whenever an error occurs on my site, I create a MyErrorClass object from the exception, store all the data from the exception in that object, and store the information in the database.

One of the exception properties I am keeping track of is the message for the error (ErrorMessage). I have an ErrorFilters table set up in the database where the user can filter errors based on the ErrorMessage. So say you are getting a ton of errors that say "System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.", and you want to ignore them. You just add a filter to the database with the ErrorMessage as "timeout expired", and set it to ignore.

Now, my class above is set to take an error, and decide if the error should be filtered. I'm trying to get a list of all filters that have an ErrorMessage matching that of the error.

I'm sure this is an easy fix, I just don't know how to fix it.

bdukes
  • 152,002
  • 23
  • 148
  • 175
  • This method is returning void, what is supposed to do? If it has to check if the error has to be shown, then it should return a boolean, and a fix can be found. Else, explain the question a bit better. – Alex Bagnolini Nov 09 '09 at 21:23
  • 2
    The function is doing a lot of other things that aren't relevant to the error, all that matters are those 3 lines where I'm trying to get a list of filters that match the error. I explained everything you need to know, what else are you wondering about? –  Nov 09 '09 at 21:27

2 Answers2

13

Hmm... It seems the Linq2SQL IndexOf translation is smarter than for Contains. This should work:

public static void MyFunction(MyErrorClass err)
{
    var query = DataContext.ErrorFilters;
    query = query.Where(f => err.ErrorMessage.IndexOf(f.ErrorMessage)>=0);
    List<ErrorFilter> filters = query.ToList();
    //...more code
}

In LinqPad it can be seen this uses CHARINDEX, because we've asked for more than just "contains", rather "where is it", but it is happy to work with server-side expressions.

Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
  • 2
    This is pure brilliance. People have been looking for a solution to this for years!! .Select(x=> "text1|text2|text3".IndexOf(x.column) >= 0) – benpage Aug 01 '14 at 01:16
  • @benpage In defence of the community, after I posted this answer I noted [other](http://stackoverflow.com/a/19791382/256431) [places](http://stackoverflow.com/a/7574433/256431) on SO that already mentioned this concept years ago. – Mark Hurd Aug 08 '14 at 05:57
0

It seems you should be using f.ErrorMessage.Contains(err.ErrorMessage) - linq to sql should then convert this to WHERE ErrorFilter.ErrorMessage LIKE %err.ErrorMessage%. The problem with the way you have it is that the generated SQL would need a dynamic string to match in the where clause, and hence could only be filtered on the client.

Incidently, the var query = from filter in DataContext.ErrorFilters select filter; line is not required and you can just do:

var filters = DataContext.ErrorFilters.Where(f => f.ErrorMessage.Contains(err.ErrorMessage)).ToList();

EDIT:

Ok I see what you're trying to do now, but I'm not sure if this is possible in linq2sql. You could create a stored procedure and add that to your datacontext and do the mapping from the output to a sequence of ErrorFilter objects:

create procedure GetMatchingFilters @message varchar(500)
as
begin
    select  *
    from ErrorFilter
    where @message LIKE '%'+ErrorMessage+'%'
end

Then in your datacontext you can do:

DataContext
    .GetMatchingFilters(err.ErrorMessage)
    .Select(result => new ErrorFilter {...})
    .ToList();
Lee
  • 142,018
  • 20
  • 234
  • 287
  • The problem with that is that it would be very difficult to filter out based on the ErrorMessage. The ErrorMessage is usually very long, and you should be able to create a filter by just typing "timeout expired". Using your method, the user would have to have the ErrorMessage for the filter be exactly the same as the ErrorMessage for the error. –  Nov 09 '09 at 21:39
  • No, it should work as you described, the query will be something like SELECT * FROM ErrorFilters WHERE ErrorMessage LIKE %someString%. Unless I've misunderstood the problem... – Lee Nov 09 '09 at 21:45
  • Invert `f.ErrorMessage.Contains(err.ErrorMessage))` to `err.ErrorMessage.Contains(f.ErrorMessage))` – Alex Bagnolini Nov 09 '09 at 21:50
  • 1
    Lee: I think you may have misunderstood. Say I get an error with the message "System.Data.SqlClient.SqlException: Timeout expired.", and I have a filter with the message "timeout expired". Using your solution, it will check to see if the string "timeout expired" contains the long error message from the initial error. It should be checking to see if the long error message contains the string "timeout expired". Does that make sense? Alex: That's what I already have. –  Nov 09 '09 at 21:59
  • Thanks for the update, Lee. It looks like that will be the route I'll have to take, thanks for all your help. –  Nov 09 '09 at 23:08