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.
答案 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;
}