Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use Microsoft.Data.SqlClient.SqlException vs System.Data.SqlClient.SqlException?

Tags:

c#

sql-server

I understand that around 2019 Microsoft created Microsoft.Data.SqlClient as their replacement for System.Data.SqlClient. System.Data.SqlClient will be supported ongoing but new dev & features will all be in Microsoft.Data.SqlClient. Both of these libraries have a class named 'SqlException'.

Assuming I'm using Microsoft.Data.SqlClient everywhere then presumably relevant exceptions will be of type Microsoft.Data.SqlClient.SqlException, BUT I use a bunch of 3rd-party libraries, how can I be sure whether they'll raise a a Microsoft.Data.SqlClient.SqlException or a System.Data.SqlClient.SqlException? Does this mean in a few cases where I have catch handlers for Microsoft.Data.SqlClient.SqlException I should also check for System.Data.SqlClient.SqlException? Or is there something clever that happens which means I only need to think about Microsoft.Data.SqlClient.SqlException?

e.g. I have some old code a bit like I've shown below, written before we started using Microsoft.Data.SqlClient. I fear if I simply change it to use Microsoft.Data.SqlClient then there will be some exceptions that are System.Data.SqlClient.SqlException and my code will no longer notice them.

    private static bool HandleSqlExceptionInSomeWay(Exception ex)
    {
        var se = ex as System.Data.SqlClient.SqlException;

        if (se != null)
        {
            // ... do something with the SqlException
            return true;
        }

        return false;
    }

So should I change it to be something like this, i.e. check separately for the different types?

    private static bool HandleSqlExceptionInSomeWay(Exception ex)
    {
        // handle old SqlExceptions (e.g. from any old 
        // libraries not using MS package yet)
        var se1 = ex as System.Data.SqlClient.SqlException;

        if (se1 != null)
        {
            // ... do something with the SqlException ...

            return true;
        }

        // handle shiny new SqlExceptions 
        var se2 = ex as Microsoft.Data.SqlClient.SqlException;

        if (se2 != null)
        {
            // ... do something with the SqlException ... 

            return true;
        }

        return false;
    }
like image 861
Rory Avatar asked Sep 07 '25 18:09

Rory


1 Answers

The two classes are different but they do inherit from the same base class, DbException. That's the common class for all database exceptions though and won't have all the properties in the two derived classes

You should inspect the libraries/NuGet packages you use and ensure you use versions that support the new Microsoft.Data.SqlClient library. Mixing up data providers isn't fun and should be avoided when possible. Most popular NuGet packages use Microsoft.Data.SqlClient already.

If you can't do that, the options depend on how you actually handle database exceptions. Do you inspect the SQL Server-specific properties or not?

Another option is to postpone upgrading until all NuGet packages have upgraded too. Both libraries include native DLLs that need to be included during deployment. If you mix libraries, you'll have to include all native DLLs.

This can be painful.

Handling the exceptions

If both libraries need to be used, each exception type needs to be handled separately. Pattern matching makes this a bit easier :

switch (ex) 
{
    case  System.Data.SqlClient.SqlException exc:
        HandleOldException(exc);
        return true;
    case Microsoft.Data.SqlClient.SqlException exc:
        HandleNewException(exc);
        return true;
    case DbException exc:
        HandleDbException(exc);
        return true;
    default:
        return false;
}

Mapping Exceptions

Another option could be to map the two exception types to a new custom type that contains the interesting properties. You'd have to map both the SqlException and SqlError classes. Using AutoMapper would make this easier:

var configuration = new MapperConfiguration(cfg => {
    cfg.CreateMap<System.Data.SqlClient.SqlException, MySqlException>();
    cfg.CreateMap<System.Data.SqlClient.SqlError, MySqlError>();
    cfg.CreateMap<Microsoft.Data.SqlClient.SqlException, MySqlException>();
    cfg.CreateMap<Microsoft.Data.SqlClient.SqlError, MySqlError>();
});

This would allow mapping either exception to the common MySqlException type :

var commonExp=mapper.Map<MySqlException>(ex);
like image 165
Panagiotis Kanavos Avatar answered Sep 10 '25 06:09

Panagiotis Kanavos