0

我想知道将其中一些代码抽象为简单 DAL 的更好方法是什么。目前,我只是在修补代码,现在没有时间或不需要使用 EF、Linq2Sql 或任何 ORM。

    public string GetMySpecId(string dataId)
    {
        using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
        {

            conn.Open();

            // Declare the parameter in the query string
            using (SqlCommand command = new SqlCommand(@"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId", conn))
            {
                // Now add the parameter to the parameter collection of the command specifying its type.
                command.Parameters.Add(new SqlParameter("dataId", SqlDbType.Text));

                command.Prepare();

                // Now, add a value to it and later execute the command as usual.
                command.Parameters[0].Value = dataId;


                using (SqlDataReader dr = command.ExecuteReader())
                {
                    while (dr.Read())
                    {
                        specId = dr[0].ToString();
                    }
                }
            }
        }

        return specId;
    }

什么是从 GetMySpecId() 中提取连接、命令等的好方法,因为我将拥有大量这些功能并且不想一遍又一遍地编写 using....

4

5 回答 5

2

好吧,您可以编写自己的自定义数据访问助手来封装所有这些内容并返回一个 DataTable:

public string GetMySpecId(string dataId)
{
    DataTable result = _dbHelper.ExecuteQuery(
        @"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId",
        new SqlParameter("dataId", dataId);
    return result.Rows[0][0].ToString();
}

或者,如果您坚持使用 DataReader 的想法,您可以将委托传递给助手,该助手在 using 语句中被调用:

public string GetMySpecId(string dataId)
{
    return _dbHelper.ExecuteQuery(
        dr => 
           {
               if(dr.Read())
               {
                   return dr[0].ToString();
               }
               // do whatever makes sense here.
           },
        @"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId",
        new SqlParameter("dataId", dataId));
}

您还可以使用像Dapper这样的轻量级工具来简化一些语法并负责映射到您的数据类型。(您仍然需要处理打开连接等问题。)

更新

下面是如何编写第二个示例中使用的 ExecuteQuery 方法的示例:

public T ExecuteQuery<T>(
    Func<IDataReader, T> getResult,
    string query,
    params IDataParameter[] parameters)
{
    using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
    {
        conn.Open();
        // Declare the parameter in the query string
        using (SqlCommand command = new SqlCommand(query, conn))
        {
            foreach(var parameter in parameters)
            {
                command.Parameters.Add(parameter);
            }
            command.Prepare();
            using (SqlDataReader dr = command.ExecuteReader())
            {
                return getResult(dr);
            }
        }
    }
}
于 2012-12-04T22:25:18.893 回答
1

您可以使用 yield return 语句来将连接、命令和读取器对象保留在 using 语句中。

public class ScalarReader<T>
{
    const string MyConnectionString = "...";

    private string _returnColumn, _table, _whereCond;
    private object[] _condParams;

    public ScalarReader(string returnColumn, string table, string whereCond,
                        params object[] condParams)
    {
        _returnColumn = returnColumn;
        _table = table;
        _whereCond = whereCond;
        _condParams = condParams;
    }

    public IEnumerator<T> GetEnumerator()
    {
        using (SqlConnection conn = new SqlConnection(MyConnectionString)) {
            conn.Open();
            string select = String.Format(@"SELECT ""{0}"" FROM ""{1}"" WHERE {2}",
                                          _returnColumn, _table, _whereCond);
            using (SqlCommand command = new SqlCommand(select, conn)) {
                for (int p = 0; p < _condParams.Length; p++) {
                    command.Parameters.AddWithValue("@" + (p+1), _condParams[p]);
                }
                using (SqlDataReader dr = command.ExecuteReader()) {
                    while (dr.Read()) {
                        if (dr.IsDBNull(0)) {
                            yield return default(T);
                        } else {
                            yield return (T)dr[0];
                        }
                    }
                }
            }
        }
    }
}

你会这样称呼它

var reader = new ScalarReader<string>("specId", "MyTable", "dataId=@1", "x");
foreach (string id in reader) {
    Console.WriteLine(id);
}

请注意,我使用的是参数名称的约定。它们被命名为@1, @2, @3 ....

var reader =
    new ScalarReader<DateTime>("date", "MyTable", "num=@1 AND name=@2", 77, "joe");
于 2012-12-04T22:57:24.467 回答
0

您需要从 using 语句的中间返回一个 IDataReader,一旦这样做,您将失去连接和数据。你不能真正做你所追求的。

于 2012-12-04T22:19:34.147 回答
0

你可以做这样的事情,抱歉没有实际的代码,但它会给你这个想法。当然,必须小心地将 object[] 转换回有用的东西,但是你已经在使用 specId = dr[0].ToString();

class MyDb
{
    public MyDb()
    {
    }

    public void Initialize()
    {
        // open the connection
    }

    public void Finalize()
    {
        // close the connection
    }

    public List<object[]> Query(string command, List<SqlParameter> params)
    {
        // prepare command
        // execute reader
        // read all values into List of object[], and return it
    }
}
于 2012-12-04T22:29:34.187 回答
0

您可以创建一个基本抽象类,该类将具有一些具有所有使用和基本代码的基本功能,如下所示:

public abstract class BaseClass
{
  public abstract void myFunc(SqlConnection conn);

  public void BaseFunc()
  {      
        using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
        {
            conn.Open();
            myFunc(conn);
            ..any other base implementation...
        }
  }
}

每个派生类都将继承 BaseClass 并使用特定查询和每个派生类的所有特定内容实现抽象 MyFunc。您将从基础抽象类的 BaseFunc 函数外部调用。

于 2012-12-04T22:30:28.690 回答