创建通用Data Wrapper的问题

时间:2014-02-03 19:57:14

标签: c# .net generics .net-4.0 data-access-layer

我在创建(通常)通用数据访问包装器时遇到问题

代码

/// <summary>
/// Get the results of a stronly-typed IList Object
/// </summary>
/// <typeparam name="T">Strongly-Typed class of objects that should be returned</typeparam>
/// <param name="_DBType">The type of database to use</param>
/// <param name="_Qry">The query to run</param>
/// <param name="_QryType">The Query Type to run</param>
/// <param name="_ParamNames">The Parameters' names to pass to the query, if any</param>
/// <param name="_ParamVals">The Parameters' values to pass to the query, if any</param>
/// <param name="_ParamDTs">The Parameters' data types to pass to the query, if any</param>
/// <param name="_ShouldCache">Should we cache the response</param>
/// <param name="_CacheID">Cache item name</param>
/// <returns>Strongly Typed ilist of objects</returns>
public static IList<T> GetResults<T>(Enumerators.DatabaseTypes _DBType, 
                                    string _Qry, 
                                    CommandType _QryType,
                                    string[] _ParamNames = null,
                                    object[] _ParamVals = null,
                                    Enumerators.DataTypes[] _ParamDTs = null,
                                    bool _ShouldCache = false,
                                    string _CacheID = "") where T : new()
{
    // Create a reference to a potential already cached IList
    IList<T> _CachedItem = _Cache.Get<IList<T>>(_CacheID);
    // If we're already cached, there's no need to fire up the data access objects, so return the cached item instead
    if (_CachedItem != null && _ShouldCache)
    {
        return _CachedItem;
    }
    else
    {
        // Fire up our data access object
        switch (_DBType)
        { 
            case Enumerators.DatabaseTypes.SqlServer:
                SqlServer.Access db = new SqlServer.Access();
                break;
            case Enumerators.DatabaseTypes.SqlCE:
                SqlCE.Access db = new SqlCE.Access();
                break;
            case Enumerators.DatabaseTypes.MySql:
                MySql.Access db = new MySql.Access();
                break;
            case Enumerators.DatabaseTypes.OLE:
                Ole.Access db = new Ole.Access();
                break;
            case Enumerators.DatabaseTypes.ODBC:
                Odbc.Access db = new Odbc.Access();
                break;
            default:
                db = null;
        }
        using (db)
        {
            try
            {
                // create a new ilist reference of our strongly typed class
                IList<T> _Query = default(IList<T>);
                // set the query type
                db.QueryType = _QryType;
                // set the query text
                db.Query = _Qry;
                // make sure we've got some parameters, if we do the set them to our db access object
                if (_ParamNames != null)
                {
                    // set the parameter names
                    db.ParameterNames = _ParamNames;
                    // set the parameter values
                    db.ParameterValues = _ParamVals;
                    // set the parameter data types
                    db.ParameterDataTypes = _ParamDTs;
                }
                // start using our db access :)  Fire off the GetResults method and return back a SqlDataReader to work on
                using (DbDataReader r = db.GetResults())
                {
                    // make sure the data reader actually exists and contains some results
                    if (r != null)
                    {
                        // map the data reader to our strongly type(s)
                        _Query = Map<T>(r);
                    }
                    r.Close();
                }
                // check if we should cache the results
                if (_ShouldCache)
                {
                    // if so, set the query object to the cache
                    _Cache.Set<IList<T>>(_Query, _CacheID);
                }
                // return our strongly typed list
                return _Query;
            }
            catch (DbException dEx)
            {
                // Catch an exception if any, an write it out to our logging mechanism, in addition to adding it our returnable message property
                _Msg += "Wrapper.GetResults Exception: " + dEx.Message + db.Message;
                ErrorReporting.WriteEm.WriteItem(dEx, "o7th.Class.Library.Data.Wrapper.GetResults", _Msg);
                // make sure this method returns a default List
                return default(IList<T>);
            }
            catch (Exception ex)
            {
                // Catch an exception if any, an write it out to our logging mechanism, in addition to adding it our returnable message property
                _Msg += "Wrapper.GetResults Exception: " + ex.Message + db.Message;
                ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.Wrapper.GetResults", _Msg);
                // make sure this method returns a default List
                return default(IList<T>);
            }
        }
    }
}

访问类 - SqlServer

using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace o7th.Class.Library.Data.SqlServer
{
internal class Access : IDisposable
{

#region "Properties"

    // Set the type of query we are running
    private CommandType _QT;
    internal CommandType QueryType { set { _QT = value; } }

    // Set the actual query text to run
    private string _Qry;
    internal string Query { set { _Qry = value; } }

    // Set the parameter names if there are any
    private string[] _PNs;
    internal string[] ParameterNames { set { _PNs = value; } }

    // Set the parameter values if there are any
    private object[] _PVs;
    internal object[] ParameterValues { set { _PVs = value; } }

    // Set the actual Sql Data Types if there are any
    private DataTypes[] _DTs;
    internal DataTypes[] ParameterDataTypes { set { _DTs = value; } }

    // Check to see if there are any parameters passed
    private bool AreParams() {
        // Check to see if the values and names are null first
        if (_PVs != null && _PNs != null) {
            try {
                Type _t_pv = _PVs.GetType();
                Type _t_pn = _PNs.GetType();
                if (_t_pv.IsArray && _t_pn.IsArray) {
                    return (_PVs.Length > 0 && _PNs.Length > 0) ? true : false;
                } else {
                    return false;
                }
            } catch {
                // yes I meant to do this, we really don't need to get the exception here
                return false;
            }
        } else {
            return false;
        }
    }

    // Get a return message if any
    private string _Msg;
    internal string Message { get { return _Msg; } }

    // Set the official Sql Reader object
    private SqlDataReader _Rdr;
    // Set the official Sql Connection object
    private SqlConnection _Conn;
    // Set the official Sql Command object
    private SqlCommand _Cmd;
    // Hack for seeing if we're disposed already
    private bool disposedValue;

#endregion

    // Constructor
    internal Access() {
        Invoke();
    }

    // Official Constructor.  We can thread these 2 becuase they are not being used yet, and it makes it slightly more efficient
    internal void Invoke() {
        try { 
            Parallel.Invoke(() => {
                _Conn = new SqlConnection(AssemblyProperties.GetConnectionString());
            }, () =>
            {
                _Cmd = new SqlCommand();
            });
        }
        catch (SqlException dEx)
        {
            // Catch an exception if any, an write it out to our logging mechanism, in addition to adding it our returnable message property
            _Msg = "Access.Invoke Exception: " + dEx.Message;
            ErrorReporting.WriteEm.WriteItem(dEx, "o7th.Class.Library.Data.SqlServer.Access.Invoke", _Msg);
        }
        catch (Exception ex)
        {
            _Msg = "Access.Invoke Exception: " + ex.Message;
            ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.SqlServer.Access.Invoke", _Msg);
        }
    }

    /// <summary>
    /// Return a SqlDataReader based on the properties passed to this class
    /// </summary>
    /// <returns></returns>
    internal SqlDataReader GetResults()
    {
        try {
            // check for parameters
            if (AreParams()) {
                PrepareParams(_Cmd);
            }
            // set our connection
            _Cmd.Connection = _Conn;
            // set the type of query to run
            _Cmd.CommandType = _QT;
            // set the actual query to run
            _Cmd.CommandText = _Qry;
            // open the connection
            _Cmd.Connection.Open();
            // prepare the command with any parameters that may have gotten added
            _Cmd.Prepare();
            // Execute the SqlDataReader, and set the connection to close once returned
            _Rdr = _Cmd.ExecuteReader(CommandBehavior.CloseConnection);
            // clear out any parameters
            _Cmd.Parameters.Clear();
            // return our reader object
            return (!_Rdr.HasRows) ? null : _Rdr;
        }
        catch (SqlException SqlEx)
        {
            _Msg += "Acccess.GetResults SqlException: " + SqlEx.Message;
            ErrorReporting.WriteEm.WriteItem(SqlEx, "o7th.Class.Library.Data.SqlServer.Access.GetResults", _Msg);
            return null;
        }
        catch (Exception ex) {
            _Msg += "Acccess.GetResults Exception: " + ex.Message;
            ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.SqlServer.Access.GetResults", _Msg);
            return null;
        }
    }

    /// <summary>
    /// Execute a non-return query, and return the success
    /// </summary>
    /// <returns></returns>
    internal bool Execute() {
        try {
            // check for parameters
            if (AreParams()) {
                PrepareParams(_Cmd);
            }
            // set our connection
            _Cmd.Connection = _Conn;
            // set the type of query to run
            _Cmd.CommandType = _QT;
            // set the actual query to run
            _Cmd.CommandText = _Qry;
            // open the connection
            _Cmd.Connection.Open();
            // prepare the command with any parameters that may have gotten added
            _Cmd.Prepare();
            // execute the non-returnable query against the database
            _Cmd.ExecuteNonQuery();
            // clear out any parameters
            _Cmd.Parameters.Clear();
            // executed successfully (otherwise would have thrown an exception)
            return true;
        }
        catch (SqlException SqlEx)
        {
            _Msg += "Access.Execute SqlException: " + SqlEx.Message;
            ErrorReporting.WriteEm.WriteItem(SqlEx, "o7th.Class.Library.Data.SqlServer.Access.Execute", _Msg);
            return false;
        }
        catch (Exception ex) {
            _Msg += "Access.Execute Exception: " + ex.Message;
            ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.SqlServer.Access.Execute", _Msg);
            return false;
        }
    }

    /// <summary>
    /// Execute a query with a return value.  Used in Selecting the ID of the last inserted record.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="_DefVal"></param>
    /// <returns></returns>
    internal T ExecuteWithReturn<T>(T _DefVal) {
        try {
            T _Ret;
            // check for parameters
            if (AreParams()) {
                PrepareParams(_Cmd);
            }
            // set our connection
            _Cmd.Connection = _Conn;
            // set the type of query to run
            _Cmd.CommandType = _QT;
            // set the actual query to run
            _Cmd.CommandText = _Qry;
            // open the connection
            _Cmd.Connection.Open();
            // prepare the command with any parameters that may have gotten added
            _Cmd.Prepare();
            T _T = (T)_Cmd.ExecuteScalar();
            _Ret = (_T is DBNull) ? default(T) : _T;
            // clear out _T
            _T = default(T);
            // clear out any parameters
            _Cmd.Parameters.Clear();
            // return the single return value from the query run
            return _Ret;
        }
        catch (SqlException SqlEx)
        {
            _Msg += "Access.ExecuteWithReturn SqlException: " + SqlEx.Message;
            ErrorReporting.WriteEm.WriteItem(SqlEx, "o7th.Class.Library.Data.SqlServer.Access.ExecuteWithReturn", _Msg);
            return default(T);
        } catch (Exception ex) {
            _Msg += "Access.ExecuteWithReturn Exception: " + ex.Message;
            ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.SqlServer.Access.ExecuteWithReturn", _Msg);
            return default(T);
        }
    }

    /// <summary>
    /// Prepare our parameters, adding them and forcing a valid data length
    /// </summary>
    /// <param name="objCmd"></param>
    protected void PrepareParams(SqlCommand objCmd) {
        try  {
            // set our initial Data Size
            int _DataSize = 0;
            // get the number of Parameter Values passed in
            int _PCt = _PVs.GetUpperBound(0);
            // begin array check
            Type _t_dt = _DTs.GetType();
            // start looping over our parameters
            for (int i = 0; i <= _PCt; ++i) {
                // make sure that the data types are actually an array
                if (_t_dt.IsArray) {
                    // select which datatype, and force the official size
                    switch ((int)_DTs[i]) {
                        case 0:
                        case 33:
                        case 6:
                        case 9:
                        case 13:
                        case 19:
                            _DataSize = 8;
                            break;
                        case 1:
                        case 3:
                        case 7:
                        case 10:
                        case 12:
                        case 21:
                        case 22:
                        case 23:
                        case 25:
                            _DataSize = _PVs[i].ToString().Length;
                            break;
                        case 2:
                        case 20:
                            _DataSize = 1;
                            break;
                        case 5:
                            _DataSize = 17;
                            break;
                        case 8:
                        case 17:
                        case 15:
                            _DataSize = 4;
                            break;
                        case 14:
                            _DataSize = 16;
                            break;
                        case 31:
                            _DataSize = 3;
                            break;
                        case 32:
                            _DataSize = 5;
                            break;
                        case 16:
                            _DataSize = 2;
                            break;
                    }
                    // add our parameter to the command object
                    objCmd.Parameters.Add(_PNs[i], (SqlDbType)_DTs[i], _DataSize).Value = _PVs[i]; 
                } else {
                    // if the datatypes were not set, try to add them generically
                    objCmd.Parameters.AddWithValue(_PNs[i], _PVs[i]);
                }
            }
            // clean up
            _PNs = null;_PVs = null;_DTs = null;
        } catch (Exception ex) {
            _Msg += "Access.PrepareParams Exception: " + ex.Message;
            ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.SqlServer.Access.PrepareParams", _Msg);
        }
    }

#region "Dispose Support"

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue && disposing) {
            try
            {
                _Qry = string.Empty;
                _Rdr.Close();
                _Rdr.Dispose();
                _Cmd.Connection.Close();
                _Cmd.Dispose();
                if (_Conn.State == ConnectionState.Open)
                {
                    SqlConnection.ClearAllPools();
                    _Conn.Close();
                    _Conn.Dispose();
                }
                _Msg = null;
            }
            catch(Exception ex) {
                ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.SqlServer.Access.Dispose", "");
            }
        }
        disposedValue = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

#endregion

}
}

我遇到的问题是,因为我需要switch语句来选择应该使用哪个数据库Access方法,所以它会在整个地方抛出The name 'db' does not exist in the current context个错误。

我还尝试var db;语句前switch Implicitly-typed local variables错误。

我不知道在实际使用它之前将使用哪种类型的数据库,那么我该如何确保它有效呢?

        IDbAccess db;
        switch (_DBType)
        { 
            case Enumerators.DatabaseTypes.SqlServer:
                SqlServer.Access db = new SqlServer.Access();
                break;
            case Enumerators.DatabaseTypes.SqlCE:
                SqlCE.Access db = new SqlCE.Access();
                break;
            case Enumerators.DatabaseTypes.MySql:
                MySql.Access db = new MySql.Access();
                break;
            case Enumerators.DatabaseTypes.OLE:
                Ole.Access db = new Ole.Access();
                break;
            case Enumerators.DatabaseTypes.ODBC:
                Odbc.Access db = new Odbc.Access();
                break;
            default:
                db = null;
        }

正在产生Cannot implicitly convert type 'SqlCE.Access to SqlServer.Access'个错误,以及A local variable 'db' is already defined in this scopeA local variable named 'db' cannot be declared in this scope because it would give a different meaning to 'db' which is already used in a parent of current scope to denote something else

1 个答案:

答案 0 :(得分:2)

所有这些各种数据库提供程序应该具有它们都继承的某种基类或它们都实现的接口。该基类/接口应具有稍后在该方法中使用的所有操作。在switch之前创建该基本类型/接口的变量,然后在每个case中为该变量赋值。