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

时间:2015-07-31 19:22:15

标签: c# sql .net sql-server sqlite

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.

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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
    }
}

答案 2 :(得分:0)

将特定于数据库的知识移动到SQLManager类中(或创建自己的包装类):

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;
}
相关问题