简介
前阵子我变得沮丧的。NET中没有按锟t提供任何与事实查询数据库,它小于约8条线路的方法。我每次想要使数据库查询,甚至运行在SQL存储过程,我发现了它不可能没有至少3套波浪括号。首先,我打开SQL连接,然后我创建的SQL命令,然后使用数据读取器通过数据运行和得到什么我想它。所有的地方我的代码有这样的结构:

List<string> result = new List<string>();
using (SqlConnection cn = new SqlConnection("Data Source=DatabaseServer;
                                             Initial Catalog=Database;
                                             User ID=UserID;Password=Password")) {
    cn.Open();
    using (SqlCommand cm = cn.CreateCommand()) {
        cm.CommandText = "mystoredproc";
        cm.CommandType = CommandType.StoredProcedure;
        cm.Parameters.AddWithValue("@param1", "1");
        cm.Parameters.AddWithValue("@param2", "2");
        using (SqlDataReader dr = cm.ExecuteReader()) {
            if (dr.HasRows) {
                while (dr.Read()) {
                    result.Add(dr.GetString(0));
                }
            }
        }
    }
}
return result;

这样写的东西,可以得到很乏味,虽然我有一种倾向,很快类型,这仍然成为不外乎死记硬背浪费更多的时间。在努力解决这个问题,我创建了两班SqlReader和SQLData。这两个类是可序列化的。SqlReader类
SqlReader类可以执行查询,使用存储过程和文本的命令类型。区分用户在查询字符串中的空间很简单锟s意向。如果有一个,然后锟s文本的CommandType,如果有锟s没有,那么它锟s存储过程。
类创建一个静态构造函数如下: {C}
它有两个参数,第一个SQL连接字符串,第二个是实际的查询。如果这是一个存储过程,然后查询可能如下所示:
SqlReader sr = SqlReader.Create("Data Source=DatabaseServer;Initial Catalog=Database;
                                 User ID=UserID;Password=Password", "mystoredproc");

再次SqlReader类本身是不够聪明,发现您是否要执行一个存储过程或文本命令。构造函数看起来像这样的代码:
/// <summary>
/// Creates a SqlReader object with CommandType of Text
/// </summary><
/span>
/// <param name="connectionString">The connection string to use to connect to 
///                                   the server.&gt/param>
/// <param name="commandText">The text to execute on the SQL server.&gt/param>
public static SqlReader Create(string connectionString, string commandText) {
    SqlReader sr = new SqlReader();
    sr._connectionString = connectionString;
    sr._commandText = commandText;
    if (commandText.Trim().Contains(" "))
        sr._commandType = CommandType.Text;
    else
        sr._commandType = CommandType.StoredProcedure;
    return sr;
}

注意,CommandType设置查询文本的基础上。如果有锟s一个空格,然后的CommandType是文字,如果没有空间,然后键入命令是一个存储过程。
让锟s说,你需要添加参数的存储过程。下面将做的伎俩:
SqlReader sr = SqlReader.Create("Data Source=DatabaseServer;Initial Catalog=Database;
                                 User ID=UserID;Password=Password", "mystoredproc")
                                 .AddParam("@param1", "1").AddParam("@param2", "2");

现在我们锟v个人增加了两个参数,我们的查询,第一个是@ param1和第二@ param2的。每个AddParam方法返回一个新的SqlReader对象,所以在这个过程中有一个递归排序,将填补参数。使用这个系统,可以无限数量的参数添加到查询。
现在执行的。有两种方法执行的executeQuery()的ExecuteNonQuery()。这些对应于SqlCommand类的同名方法。唯一不同的是,现在的executeQuery()返回一个SQLDATA类的ExecuteNonQuery(),而仅仅是一个void。
SqlData sd = SqlReader.Create("Data Source=DatabaseServer;Initial Catalog=Database;
                               User ID=UserID;Password=Password", "mystoredproc")
                               .AddParam("@param1", "1").AddParam("@param2", "2")
                               .Execute();

请注意,我锟v个人改变的类型我们新创建的变量到SQLDATA类型,这是因为Execute()方法返回一个SQLData对象,而不是一个SqlReader对象。这是很重要的原因有几个,但被人理解,我要解释SQLData的类。SQLData的类从SQL查询中的每一行存储在一个SqlRow的类,它维护的价值观和每行的列名。这些行的集合,使得SQLData的类。 SQLData的类的几种方法获取值,其中有几个重载:GetValueList,GetStringList,GetInt32List,GetInt64List,GetValue的,ISNULL的GetString,GetInt32等和GetInt64。 list命令将列名或0的列ID,将返回一个列表内,特别是列的所有值。这是伟大的迭代循环。我有看起来类似下列的代码:
foreach (string s in SqlReader.Create("Data Source=DatabaseServer;
                     Initial Catalog=Database;User ID=UserID;Password=Password", 
                     "mystoredproc").AddParam("@param1", "1").AddParam("@param2", "2")
                     .Execute().GetStringList(0))
    Console.WriteLine(s);

这将写入控制台从最左边的一列的每一个字符串返回执行myst​​oredproc @ PARAM1设置为1,@ param2的设置为2。
的方法,唐锟t重载四种方式返回一个列表。前两个重载唐锟t表示成一排,将始终返回值,从查询返回的第一行。他们可以被称为通过指定的列数或列名。第二个两个重载请致电1 -行数,行和列名或列号。这样,可用于其他迭代。
static void Main(string[] args) {
    SqlData sd =SqlReader.Create("Data Source=DatabaseServer;Initial Catalog=Database;
                                  User ID=UserID;Password=Password", "mystoredproc")
                                  .AddParam("@param1", "1").AddParam("@param2", "2")
                                  .Execute();
    for (int i = 1; i < sd.RowCount; i++) {
        Console.WriteLine(string.Format("Data from column 1: {0}, 
		                         Data from column 2: {1}", sd.GetString(i, 0),
                                         sd.GetString(i, 1)));
    }
}
SqlReader类的心脏 - 查询
如果你锟v个人作出这一步,这里锟s有趣的东西。心脏SqlReader类的Execute方法。这是发生的所有有趣的工作。这里锟s的代码:
/// <summary>
/// Executes a query.
/// </summary><
/span>
public SqlData Execute() {
    if (_hasRun)
        _sqlData = new SqlData();
    _hasRun = true;
    if (string.IsNullOrEmpty(_connectionString))
        throw new Exception("Morton's Common Tasks - SqlReader - 
		             No Connection String Entered");
    if (string.IsNullOrEmpty(_commandText))
        throw new Exception("Morton's Common Tasks - SqlReader - 
		             No Command to Perform");
    using (SqlConnection cn = new SqlConnection(_connectionString)) {
        cn.Open();
        using (SqlCommand cm = cn.CreateCommand()) {
            cm.CommandType = _commandType;
            cm.CommandText = _commandText;
            foreach (KeyValuePair<string, object> kvp in _parameters)
                cm.Parameters.AddWithValue(kvp.Key, kvp.Value);
            if (_returnData) {
                using (SqlDataReader dr = cm.ExecuteReader()) {
                    if (dr.HasRows) {
                        while (dr.Read()) {
                            SqlRow sqlRow = new SqlRow();
                            for (int i = 0; i < dr.FieldCount; i++) {
                                if (string.IsNullOrEmpty(dr.GetName(i)))
                                    sqlRow.AddSqlData("column_" + i.ToString(), 
                                                       dr.GetValue(i));
                                else
                                    sqlRow.AddSqlData(dr.GetName(i).ToLower(), 
                                                      dr.GetValue(i));
                            }
                            _sqlData.Add(sqlRow);
                        }
                    }
                }
            } else {
                cm.ExecuteNonQuery();
            }
        }
              
    }
    return this.Result;
}

的行的第一对夫妇检查,看看如果查询运行或不。如果有,那么我们需要重新设置将返回的值。我们将抛出一个例外,如果我们的查询和连接字符串是空的,然后我们锟l升开始查询。
首先,我们使用连接字符串连接到服务器,并打开连接。命令类型和命令文本设置。在此之后,参数添加到命令。
_returnData变量默认为true,并可以设置虚假的ExecuteNonQuery()方法,如果它被称为。如果_returnData是真的,那么我们将寻找一个结果。如果我们,然后我们创建一个SqlDataReader对象,并添加我们到SqlRow的所有数据,那么我们所有的行SQLData对象。如果有锟s没有名称的列,那么列名是编程方式设置一个任意值。在这种情况下,,将它们设置column_1,column_2等???如果有一个列名,然后用于实际的列名。
最后,在结束,结果将被返回。行锟return this.Result??使用下面的属性返回的_sqlData对象。
/// <summary>
/// An object returning the result of a Sql Query.
/// </summary><
/span>
public SqlData Result {
    get {
        return _sqlData;
    }
}
结论
我锟v个人一直使用这个类在某些产品级应用现在一段时间没有问题,它已经救了我的时间在查询建设的巨大金额。
随意使用此代码。让我知道它是如何工作的!

回答

评论会员:sahami 时间:2011/12/07
您好

我相信有一个bug,当设置的SqlReader命令文本。

/ / /

/ / / SqlReader对象的命令文本。 / / /
公共字符串的CommandText {
& #160; 得到{
 0; 返回_commandText;
 60; }
集合{
_connectionString =值; <---
}
}

关于
Arash的
评论会员:DavidMorton 时间:2011/12/07
是啊,我敢肯定有。拉尔夫的意见,并使用下面的SQL数据访问块。这是当我在我的"重写一切"的编程阶段。很抱歉,但微软已经实施了更加潇洒,那么我做过的,所以我不支持这个在所有
评论会员:。LemmyCC 时间:2011/12/07
在您的原始动机代码,是不是你的行

如果(dr.HasRows){

多余的,因为阅读()将返回假呢?

不错的文章虽然
评论会员:拉尔夫Willgoss 时间:2011/12/07
嗨,

你检查出{A}?

它减少了代码量,与一些静态类的简单使用一条线,他们创造了

下载页面上有一个链接,这将给你如何适应与MS的模式和做法的东西的详细信息。

至于,
拉尔夫
评论会员:jttraino 时间:2011/12/07
是啊,拉尔夫有一个好主意,看看Microsoft数据访问块

我最近建议,一个我的作品的开发者时,他告诉我他写他自己。我不知道如果他把我的意见。

在此有关其使用的网站有一个很好的文章:


约翰

{S0}
评论会员:pric0112 时间:2011/12/07
我一直在使用一类是我自己做的东西非常相似。虽然是看起来像一个比我更好地贯彻落实。

建议:使用连接字符串的名称,而不是原始的连接字符串(即在一个web.config或app.config中文件中定义)。这将使你的例子,外观整洁,并允许更多的灵活性。


评论会员:BlackTigerAP 时间:2011/12/07

创建过程DBO [存储过程] 打印"存储过程"
调用此过程。 {S0}

评论会员:大卫莫顿 时间:2011/12/07
大点。我不知道这是可能的,但显然这是。我可以把某个尽快更新。话又说回来,数据访问代码块的问题,我可能不会。只要使用的那一个。看来,创建此代码,我已经有点重复的代码,我不完全知道存在。哦,好。这是一个有趣的练习,我学到了很多东西。

大卫
评论会员:sys64738 时间:2011/12/07
链接不工作
评论会员:托尼贝穆德斯 时间:2011/12/07
源代码的链接被打破。
评论会员:罗布格雷厄姆 时间:2011/12/07
我觉得你SqlReader类可以被改善,如果你更加紧密地跟随微软的指引类库开发,特别是关于异常,:你应该使用的更具体的ArgumentException,而不是的通用异常{A3} ]。此外,依靠区分命令名称和查询字符串在字符串空间似乎有点kludge,将不是一个布尔参数更有意义吗?

评论会员:大卫莫顿 时间:2011/12/07
评论表示感谢。我会看到的ArgumentException类,我可能会更新库。至于使用的空间,以区分存储过程和检索查询,我设置类来区分使用这个功能的重要原因之一是易用性。如果我改变了类,并要求用户把一个布尔值,我可能也有用户只需输入他们希望使用的CommandType枚举的成员,并在这种情况下,我会继续,并允许使用的TableDirect程序。我一直在使用了几个月,我还没有遇到一个情况,其中一个文本命令不包括在查询的空间,或存储过程包含在它的名字空间。 (事实上​​,它可能有一个程序的名称空间存储过程。)但是,我可以如果我得到了足够的兴趣,抛出另一种创建方法重载,和用户可以手动指示的类型他们希望程序执行。

这个类并不是完全取代ADO.NET系统内置的功能。NET中,相反却是最常见的情况,旨在提高编码效率。
评论会员:aquatarian 时间:2011/12/07
一般

"神奇"的字符控制程序逻辑永远是值得商榷的。在一个神奇的字符可能来通过用户输入的情况下,它可以成为彻头彻尾的危险。想想注入式攻击。

因此,使用此代码在本地的应用程序的SQL完全是硬编码由开发商可能不可怕。
小心的发育尝试使用这个代码在一个Web应用程序或其他非控制的情况。
这只是坏的做法,因为你要担心这么多的其他途径,一个简单的布尔参数时只会删除所有疑问,并添加一个微小的打字开销。

关于作者

大卫莫顿
中国
我是一名编程爱好者,
谢谢orcode.com为我们提供一个学习和分享的平台。
有什么问题。可以就本内容回复,我看到时。会尽量回复的。
或代码 网站备案号:粤ICP备15020848号-1