【问题标题】:How to create a DbCommand that is compatible with SQL Server and SQLite without a large condition?如何在没有大条件的情况下创建兼容 SQL Server 和 SQLite 的 DbCommand?
【发布时间】:2015-07-31 19:22:14
【问题描述】:

你好,假设我有一个 C# 代码

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

效果很好。当然,在我的生产代码中,它更大,并且有更多的位置可以为不同的命令执行类似的操作。

我的问题是有没有办法让这个更短?除了调用不同的构造函数之外,我不希望复制和粘贴基本上做同样事情的代码。

非常感谢您。

【问题讨论】:

  • 我对SQL Lite不太了解,但单独做一个过程并调用它们
  • 创建一个自定义类来处理计数的参数和循环的传递
  • 在您的 InsertCommand 上使用 Facade 模式和/或将参数创建包装到类似 (CreateParam) 的位置并在那里检查。
  • 使用许多 ORM-DAO 包装器之一可以简化编写此类跨供应商代码。

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


【解决方案1】:

这样就可以了,我省略了细节,但你可以弄清楚:

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

CustomSqlParameter 的代码应该很明显

【讨论】:

  • @user2864740 - 你必须写 - 你看第一个参数并返回正确的结果。
  • @user2864740 - 名字不好...让我来解决这个问题。
  • @user2864740 -- 在那里,我将MySqlParameter 更改为CustomSqlParameter -- 而MySqlParameter 不是包含在C# 库中的名称,我知道你会感到困惑。
【解决方案2】:

就设计和可测试性而言,我认为像您的示例那样将事物结合起来是不正确的。

假设某事仅针对一个数据库进行更改,并且您需要更改 INSERT 查询,这会导致问题,因为相同的查询用于其他数据库。

其实你可以创建PersonRepository抽象:

public interface IPersonRepository
{
    void Add(IPerson person)
}

并创建该接口的两个实现:

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

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

【讨论】:

  • 那么数据库的内容(SQL 和 SQLite)将被同步。所以为了这个目的,我不希望每个存储库都有单独的实现。
  • 这取决于您,但这可能会给您的数据访问增加 if-else 语句的负担。条件将无处不在,传播您所有的数据访问代码。在@Hogan 方法中,即使为 SqlServer 和 SQLite 添加了相同的参数,我认为在某些情况下这是不可能的,例如DateTime。这会产生更多的条件。
  • 我同意这种做法。但是,我将创建一个“公共抽象类 PersonBaseRepository”,上面的每个具体实现。然后“共享”代码可以进入基类。但这是一个更好的主意...摆脱 if/else 语句并使用 OO
【解决方案3】:

将特定于数据库的知识移动到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;
}

【讨论】:

    猜你喜欢
    • 2011-03-30
    • 2012-01-17
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    相关资源
    最近更新 更多