简体   繁体   中英

How to create a DbCommand that is compatible with SQL Server and SQLite without a large condition?

HI lets say I have a C# code

private const string INSERT = "INSERT INTO Person VALUES (@FirstName, @LastName)";

public static DbCommand INSERTCOMMAND(IPerson person)
{
    DbCommand command = null;
    var sqlParams = new List<DbParameter>();

    if(SQLManagerFactory.SQLManager is SQLServerManager)
    {
        command = new SqlCommand(INSERT);
        sqlParams.Add(new SqlParameter("@FirstName", person.FirstName);
        sqlParams.Add(new SqlParameter("@LastName", person.LastName);
    }
    else // SQLiteManager
    {
        command = new SQLiteCommand(INSERT);
        sqlParams.Add(new SQLiteParameter("@FirstName", person.FirstName);
        sqlParams.Add(new SQLiteParameter("@LastName", person.LastName);
    }

    command.Parameters.AddRange(sqlParams.ToArray());
    return command;
}

Which is working perfectly fine. Of course in my production code, it is quite bigger and has a lot more location that does the similar things for different commands.

My question is that is there way to make this shorter? I do not wish to copy and paste code which essentially does the same thing except for calling the different constructors.

Thank you very much in advance.

Something like this would be fine, I'm leaving out details but you can figure those out:

private const string INSERT = "INSERT INTO Person VALUES (@FirstName, @LastName)";

public static DbCommand INSERTCOMMAND(IPerson person)
{
    DbCommand command = null;
    var sqlParams = new List<DbParameter>();
    MySqlEnum sqlType = SQLManagerFactory.SQLManager is SQLServerManager ? MySqlEnum.SQLServer : MySqlEnum.sqlLite

    if(sqlType == MySqlEnum.SQLServer)
        command = new SqlCommand(INSERT);
    else // SQLiteManager
        command = new SQLiteCommand(INSERT);

    sqlParams.Add(new CustomSqlParameter(sqlType ,"@FirstName", person.FirstName);
    sqlParams.Add(new CustomSqlParameter(sqlType ,"@LastName", person.LastName);

    command.Parameters.AddRange(sqlParams.ToArray());
    return command;
}

The code for CustomSqlParameter should be obvious

In terms of design and testability I think it isn't right to couple things as in your example.

Imagine that something change only for one database, and you need to change INSERT query, this would cause problem because the same query is used for other database.

Actually, you could create PersonRepository abstraction:

public interface IPersonRepository
{
    void Add(IPerson person)
}

and create two implementations of that interface :

public SqlServerPersonRepository : IPersonRepository 
{
    void Add(IPerson person)
    {
        //sql server specific code
    }
}

public SqlLitePersonRepository : IPersonRepository 
{
    void Add(IPerson person)
    {
        //sqlite specific code
    }
}

Move the database-specific knowledge into the SQLManager class (or create your own classes that wrap it):

public static DbCommand INSERTCOMMAND(IPerson person)
{
    var sqlParams = new List<DbParameter>();
    var sql = SQLManagerFactory.SQLManager; // or MyOwnSQLManager

    var command = sql.CreateCommand(INSERT);
    sqlParams.Add(sql.CreateParameter("@FirstName", person.FirstName));
    sqlParams.Add(sql.CreateParameter("@LastName", person.LastName));

    command.Parameters.AddRange(sqlParams.ToArray());
    return command;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM