返回首页

简介
前阵子我变得沮丧的。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应用程序或其他非控制的情况。
这只是坏的做法,因为你要担心这么多的其他途径,一个简单的布尔参数时只会删除所有疑问,并添加一个微小的打字开销。