C#抽象和数据库层

时间:2012-12-04 22:11:48

标签: c# .net .net-3.5 data-access-layer sqlcommand

我想知道将一些代码抽象成一个简单的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()中提取连接,命令等等是一个很好的干净方法,因为我将拥有大量这些函数,并且不想一遍又一遍地使用.... / p>

5 个答案:

答案 0 :(得分: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的想法,你可以将一个委托传递给helper,它在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);
            }
        }
    }
}

答案 1 :(得分:1)

您可以使用yield return语句,以便使用语句保持连接,命令和读取器对象。

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");

答案 2 :(得分:0)

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

答案 3 :(得分: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
    }
}

答案 4 :(得分: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函数外部调用。