2

In this method

    public static void Detach()
    {
        try
        {
            using (var master = new DataContext(@"Data Source=(LocalDB)\MSSQLLocalDB;Initial Catalog=master;Integrated Security=True"))
            {
                master.ExecuteCommand(string.Format("ALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE", DatabaseFile));
                master.ExecuteCommand(string.Format("exec sp_detach_db '{0}'", DatabaseFile));
            }
        }
        catch (Exception e)
        {
           ... // add to log
        }
    }

I can receive exception

System.Data.SqlClient.SqlException (0x80131904): The database 'blablabla.mdf' does not exist. Supply a valid database name. To see available databases, use sys.databases.

This happens if Detach() is called when database is not attached.

My question is: How to swallow only this specific message to avoid logging it?

Text may be localized, so this won't work

if(!(e is SqlException && e.Message.Contains("Supply a valid database name"))) 
    ... // log 

I am not sure if error code is unique for this specific case (google proves it?)

if(!(e is SqlException && e.Message.Contains("0x80131904"))) 
    ... // log 

Of course I can do

try { ... } catch {}

But then I have no chance to get into log something unexpected, what may help me to solve problem in case it appears.

Sinatr
  • 20,892
  • 15
  • 90
  • 319

1 Answers1

6

You don't want to check the message - you want to check the SQL specific number. You can use the SqlException.Number property for this.

I would use:

// I think this is right, based on
// http://technet.microsoft.com/en-us/library/cc645936(v=sql.105).aspx
private const int DatabaseDoesNotExistCode = 15010;
...
catch (SqlException e)
{
    if (e.Number != DatabaseDoesNotExistCode)
    {
        ...
    }
}

(I would typically not catch plain Exception... but that's probably a different matter.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This doesn't work -- 0x80131904 is not code for "the database does not exist", it's an HRESULT with facility 0x13 (FACILITY_URT, where Universal Runtime is an old name for the CLR) and 0x1904 is the error code (from `corerror.h`): `COR_E_SqlException`. In other words, you have just successfully checked that the SQL exception is an SQL exception. – Jeroen Mostert Dec 12 '14 at 10:32
  • @JeroenMostert: Aha, it looks like the `Number` property is more appropriate. – Jon Skeet Dec 12 '14 at 10:34
  • 1
    And then you just throw; to rethrow those exceptions you do not want to handle. And I would make the number comparison a SWITCH ;) Unless you only have one. – TomTom Dec 12 '14 at 10:38
  • @TomTom: It depends on what you're doing with them if there are multiple codes - if you're doing the same thing, I'd just create a `List` or `HashSet` to check whether it's "one of those". – Jon Skeet Dec 12 '14 at 10:40
  • More code and slower. I let the compiler optimize that - even with 30 codes a switch is cleaner than setting up a hashtable (in code) and the compiler can optimize that. – TomTom Dec 12 '14 at 10:45
  • 1
    @TomTom: This is happening when an *exception* is thrown - I strongly suspect that the time taken to check for presence in a collection is a problem. And I'd view it as *less* code: `private static readonly List CodesToSwallow = new List { ... }` and then a single line to check... compare that with a switch with lots of cases. – Jon Skeet Dec 12 '14 at 10:46
  • I do. The switch has the numbers - with comments / names - RIGHT EHERE IN THE CODE, while your list is neither readonly (i.e. can not be optimized) now does it correlate in locality. Bad coding practices. – TomTom Dec 12 '14 at 10:48
  • @TomTom: I think we'll have to agree to disagree at this point. – Jon Skeet Dec 12 '14 at 10:50