![](/img/trans.png)
[英]Change Label Control Property Based on Data from SqlDataSource Inside a Repeater
[英]Use of SqlDataSource From Non-Control Situations
作为我在所有业务应用程序中使用的常用实用程序的一部分,我有这个代码......
using System.Web.UI.WebControls;
public class Database
{
/// <summary>
/// Creates a DataView object using the provided query and an SqlDataSource object.
/// </summary>
/// <param name="query">The select command to perform.</param>
/// <returns>A DataView with data results from executing the query.</returns>
public static DataView GetDataView(string query)
{
SqlDataSource ds = GetDBConnection();
ds.SelectCommand = query;
DataView dv = (DataView)ds.Select(DataSourceSelectArguments.Empty);
return dv;
}
/// <summary>
/// Creates a SqlDataSource object with initialized connection string and provider
/// </summary>
/// <returns>An SqlDataSource that has been initialized.</returns>
public static SqlDataSource GetDBConnection()
{
SqlDataSource db = new SqlDataSource();
db.ConnectionString = GetDefaultConnectionString(); //retrieves connection string from .config file
db.ProviderName = GetDefaultProviderName(); //retrieves provider name from .config file
return db;
}
}
然后,在我的项目中,要从数据库中检索数据,我会有一些代码,如...
DataView dv=Database.GetDataView("select mycolumn from my table");
//loop through data and make use of it
我以这种方式从人们那里获得了一些使用SqlDataSource的热量。 人们似乎并不喜欢我纯粹从代码中使用Web控件而不是将其放在ASPX页面上。 它看起来并不正确,但他们无法告诉我一个缺点。 那么,有缺点吗? 这是我的主要问题。 因为如果有很多缺点,我可能不得不改变我开发的许多内部应用程序的方式。
我的数据库类甚至可以在非ASP.NET的情况下工作,只要我添加System.Web程序集即可。 我知道它的封装尺寸略有增加,但我觉得这对于我正在编写的应用类型是值得的。 说WPF / Windows Forms / Console程序使用SqlDataSource是否有缺点?
好吧,没有硬性规则阻止任何人做这样的实现。
但是,在执行该实现之前,需要回答以下几个问题。
考虑到替换此代码是多么容易,同时消除了使用动态SQL查询传递参数的诱惑,我认为问题应该是:保持代码原样是否有任何好处?
例如:
public static class Database
{
private static readonly Func<DbCommandBuilder, int, string> getParameterName = CreateDelegate("GetParameterName");
private static readonly Func<DbCommandBuilder, int, string> getParameterPlaceholder = CreateDelegate("GetParameterPlaceholder");
private static Func<DbCommandBuilder, int, string> CreateDelegate(string methodName)
{
MethodInfo method = typeof(DbCommandBuilder).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null);
return (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), method);
}
private static string GetDefaultProviderName()
{
...
}
private static string GetDefaultConnectionString()
{
...
}
public static DbProviderFactory GetProviderFactory()
{
string providerName = GetDefaultProviderName();
return DbProviderFactories.GetFactory(providerName);
}
private static DbConnection GetDBConnection(DbProviderFactory factory)
{
DbConnection connection = factory.CreateConnection();
connection.ConnectionString = GetDefaultConnectionString();
return connection;
}
public static DbConnection GetDBConnection()
{
DbProviderFactory factory = GetProviderFactory();
return GetDBConnection(factory);
}
private static void ProcessParameters(
DbProviderFactory factory,
DbCommand command,
string query,
object[] queryParameters)
{
if (queryParameters == null && queryParameters.Length == 0)
{
command.CommandText = query;
}
else
{
IFormatProvider formatProvider = CultureInfo.InvariantCulture;
DbCommandBuilder commandBuilder = factory.CreateCommandBuilder();
StringBuilder queryText = new StringBuilder(query);
for (int index = 0; index < queryParameters.Length; index++)
{
string name = getParameterName(commandBuilder, index);
string placeholder = getParameterPlaceholder(commandBuilder, index);
string i = index.ToString("D", formatProvider);
command.Parameters.AddWithValue(name, queryParameters[index]);
queryText = queryText.Replace("{" + i + "}", placeholder);
}
command.CommandText = queryText.ToString();
}
}
public static DataView GetDataView(string query, params object[] queryParameters)
{
DbProviderFactory factory = GetProviderFactory();
using (DbConnection connection = GetDBConnection(factory))
using (DbCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
ProcessParameters(factory, command, query, queryParameters);
DbDataAdapter adapter = factory.CreateDataAdapter();
adapter.SelectCommand = command;
DataTable table = new DataTable();
adapter.Fill(table);
return table.DefaultView;
}
}
}
使用此版本,您现在可以简单安全地传递参数,而无需依赖自定义代码来尝试阻止SQL注入:
DataView dv = Database.GetDataView(
"select mycolumn from my table where id = {0} and name = {1}",
1234, "Robert');DROP TABLE Students;--");
编辑
在此答案的帮助下更新以支持不同提供商的参数。
我看到的唯一问题是
(1)这就像重新发明轮子一样。 FW3.5有企业库v5,FW4.5有v6,它有数据访问组件。 用那个。
使用EL,您可以进行调用并在Dataset
集中加载2,3,4个表。 使用您的方法,这是不可能的,当时只有一个。
企业库是Microsoft提供的完整数据访问套件。 它会处理所有细节,您只需要调用数据即可。 这是完整的数据访问层。 如果你看得更深,EL允许集成数据和缓存,以及其他东西。 但是你不必使用你不需要的东西。 如果您需要数据访问,则只能使用它。
并且(2)通常,在参考中编写具有高级组件的低级组件不是一个好主意。 任何System.Web....
都是UI和客户端相关的东西。 在分层蛋糕设计中,这就像它的顶部,数据访问在底部。 所有参考文献[另存为“普通”]应该从底部到顶部,并且它在相反的方向上。
看这张图片:
这是来自微软。 你看到了“蛋糕”的层次。 所有参考文献都在上升。 你做了什么 - 你采用了与UI相关的组件并在其中编写了数据访问。
您可以将其称为基于意见的 - 但这种观点是软件开发中的标准实践和模式。 你的问题也是基于意见的。 因为您可以将所有内容编写为单个文件,单个类,并且它将起作用。 如果需要,可以在Asp.net应用程序中设置对System.Windows.Forms
引用。 从技术上讲,这是可能的,但这是非常糟糕的做法。
您的应用程序现在具有有限的可重用性。 如果您编写需要使用相同数据访问的WPF组件或服务,该怎么办? 你必须将所有System.Web
拖入其中?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.