如何从 IDbConnection “继承” - 只需添加一个属性(DatabaseType)

Posted

技术标签:

【中文标题】如何从 IDbConnection “继承” - 只需添加一个属性(DatabaseType)【英文标题】:How to 'inherit' from IDbConnection - just add one property (DatabaseType) 【发布时间】:2012-11-28 05:40:15 【问题描述】:

你如何继承IDbConnection?我想添加一个属性(DatabaseType,例如 MS Access、SQL server、Paradox...)。据我所知IDbConnection 是一个接口,因此我相信他们希望我实现整个接口继承链中的所有成员。这似乎是很多工作。将一个属性添加到 IDbConnection 的最佳方法是什么?

更新 我想做的是这个。我有三种我经常使用的方法:ExecuteReader、ExecuteNonQuery、ExecuteNonQueryGetIdentity。它们被大量使用并具有参数(IDbConnection Conn、字符串 SQLString、object[] SQLParams)。我认为将 DatabaseType 添加到这三个方法和我所有项目方法的最佳方法是“覆盖” IDbConnection,这样我只需更新项目中的一行代码。

我想知道 DatabaseType,因为在添加参数和构建 IDbCommand 时我会做一些不同的事情。专门针对 DateTime。

例如:

public static System.Data.IDataReader ExecuteReader(System.Data.IDbConnection Conn, string SQL, object[] SQLParams)
// return IDataReader from connection, SQL string and Params. Params can be null. 

  using (var cmd = Conn.CreateCommand())
  
    cmd.CommandText = SQL;
    AddParametersToCommand(cmd, SQLParams);   // add parameters to IDbCommand object if params not null
    return cmd.ExecuteReader();  
  


private static readonly Regex regParameters = new Regex(@"@\w+", RegexOptions.Compiled);
public static void AddParametersToCommand(IDbCommand Cmd, object[] Parameters)
/* Creates and ads unique parameters to an IDbCommand object to the CommandText SQL string.
  * Tested types with SQL Update statement in MS Access/SQL Server: boolean, int, DateTime, text
  * Parameter names in CommandText must start with the '@' char and can be any unique word (letter or number).
  * E.g. calling code: cmd.CommandText = "Select * From SiteUser Where Site > @1 And User > @NewParam"
  * 
  * http://www.codeproject.com/Articles/15542/IDbDataParameter-error-in-NET  re: some DateTime issues
*/

  if (Parameters != null && Parameters.Length > 0)
  
    MatchCollection cmdParams = regParameters.Matches(Cmd.CommandText);
    var paramNames = new List<String>();
    foreach (var el in cmdParams)
    
      if (!paramNames.Contains(el.ToString()))   // only add unique parameter names
        paramNames.Add(el.ToString());
    
    IDbDataParameter dp;
    var dbType = GetDatabaseType(Cmd.Connection);
    for (int n = 0; n < Parameters.Length; n++)
    
      var param = Parameters[n];
      dp = Cmd.CreateParameter();
      dp.ParameterName = paramNames[n];
      TypeCode myTypeCode = Type.GetTypeCode(param.GetType());
      if (myTypeCode == TypeCode.DateTime)     // this workaround is needed for MS Access and SQL Server
      
        if (dbType == DatabaseType.Access)
        
          dp.DbType = DbType.DateTime;         // set dates as DbType.DateTime for MS Access and Paradox
          dp.Value = param.ToString();         // Convert.ToDateTime(param).ToString("yyyy-MM-dd hh:mm:ss"));         
          //Note: MS access cannot store years before December 30, 1899. They will be stored for some other year.
          // for example. Jan 1 0001 will be stored as 2001.
        
        else if (dbType == DatabaseType.MSSql)
        
          dp.DbType = DbType.DateTime2;        // set dates as DbType.DateTime2 for SQL Server
          dp.Value = param.ToString();
        
      
      else
        dp.Value = param;
      Cmd.Parameters.Add(dp);
     // for n
   // if

【问题讨论】:

您想这样做的原因是什么?根据您想要的原因,可能有不同的方法来做到这一点。 接口不是继承的——它们是被实现的。你到底想做什么?如果您只想要一个包含IDbConnection 中所有内容但使用DatabaseType 的课程,您应该选择史蒂夫的答案。 【参考方案1】:

您可以使用DatabaseType 属性创建新接口MyDbConnection,但现有的IDbConnection 实现都不会实现您的接口。

我认为您不应该关心您使用的是IDbConnection 的哪个实现(MS Access、SQL 服务器、Paradox 等)。这就是我们有这个抽象和DbProviderFactory 类的原因,它们完全是我们正在使用的数据库的抽象类型。

顺便说一句,您始终可以检查IDbConnection 实例的类型,以查看您正在使用哪个实现(如果您真的需要它)。您的另一个选择(如果您真的需要该属性) - 在 IDbConnection 实例上创建装饰器:

public class MyDbConnection : IDbConnection

    private IDbConnection _connection;

    public MyDbConnection(IDbConnection connection)
    
       _connection = connection;
    

    // here goes your property
    public string DatabaseType  get; set; 

    public void Close()
    
        _connection.Close();
    

    public IDbTransaction BeginTransaction(IsolationLevel il)
    
        return _connection.BeginTransaction(il);
    

    // implement other IDbConnection members by delegating work to _connection

你可以在任何地方使用这个装饰器作为IDbConnection,但你的属性也将可用。

【讨论】:

在更新的问题详细信息中,我解释了为什么在更新 MS Access、SQL Server、Paradox 等中的早期 DateTime 字段时我需要了解基础数据库类型(而不仅仅是连接类型)。 @user610064 很有趣 - 您的应用程序使用1899之前的日期? 好吧,我只承认过去的时间。在某些情况下,我们一直在使用 DateTime 来存储经过的时间……当时它非常方便。现在将 MS Access 转换为 SQL Server... @user610064 如果您仅对 DateTime 有问题,则只需提取将创建 DbParameter 的方法,即AddParameter(command, name, object)。并从您的 ExecuteXXX 方法中调用该方法。【参考方案2】:

DbConnection 实现接口 IDbConnection。您可以扩展它(它必须实现所有接口方法)

【讨论】:

以上是关于如何从 IDbConnection “继承” - 只需添加一个属性(DatabaseType)的主要内容,如果未能解决你的问题,请参考以下文章

小巧玲珑。 IDbConnection 和 IDbTransaction

注入连接字符串与 IDbConnection

将 BeginTransaction 与 Dapper.IDbConnection 一起使用的正确方法

休眠一个 isession 相同的 idbconnection

.Net 核心依赖注入 IdbConnection

具有持久 HTTP 连接的 IDbConnection 生命周期管理