我在PHP中使用了postgreSQL,这很简单:当你进行查询时,你会这样做:
$result = pg_query($conn, "SELECT author, email FROM authors WHERE dest='" + pg_escape_string($s) + "'");
简单。安全(据我所知)。
现在我想在C#中用SQLite做同样的事情:
SQLiteCommand query = m_conn.CreateCommand();
query.CommandText = "SELECT author, email FROM authors WHERE dest=@param";
query.Parameters.Add("@dest", SqlDbType.String).Value = s;
m_datareader = query.ExecuteReader();
是不是有点矫枉过正?如果没有,为什么?
据我所知,最后,发送到数据库的字符串仍然是一个字符串,为什么要通过这个而不是仅手动清理不安全的字符串?如果在ASP .NET中将一些不安全的文本打印到HTML,那么它也是
htmlAdd.Text("<div>@param1</div>");
htmlAdd.Parameters.Add("@param1").Value = unsafeUsername;
我想做这个课程:
class QueryResultSet
{
public QueryResultSet(SQLiteConnection conn, string queryText)
{
m_conn = conn;
m_conn.Open();
SQLiteCommand query = m_conn.CreateCommand();
query.CommandText = queryText;
m_datareader = query.ExecuteReader();
}
public object this[string key]
{
get { return m_datareader[key]; }
}
public bool Read()
{
return m_datareader.Read();
}
~QueryResultSet()
{
m_conn.Close();
}
private SQLiteConnection m_conn;
private SQLiteDataReader m_datareader;
}
但现在我必须改变方法:
public QueryResultSet(SQLiteConnection conn, string queryText, Dictionary<string,string> params)
这将导致方法之前的代码并使其大小加倍。
有任何标准方法吗?如果这个类不是一个好主意,那么如何避免为每个请求做10行呢?
答案 0 :(得分:7)
参数化查询是更好的选择,因为它们通常是类型安全的,为您处理任何转义,文字格式等,以及允许服务器/后端缓存已编译的查询以获得更好的性能。
大多数数据库引擎都允许您同时执行“普通旧sql”和参数化查询。
当然,构建完整的SQL字符串需要您了解RDBMS使用的确切格式和数据类型,因为它们各不相同。
答案 1 :(得分:2)
有一些非常有效的工具可以帮助解决这个问题。既然你有SQL并且不需要复杂性,那么像“小巧”这样的微型ORM是一个合理的选择:
var result=conn.Query<Author>("SELECT author, email FROM authors WHERE dest=@s",
new {s});
或者如果您想使用dynamic
而不是强类型:
var result=conn.Query("SELECT author, email FROM authors WHERE dest=@s",new {s});
现在还不错吗?然后你可以通过以下方式消费它:
foreach(var obj in result) {
Console.WriteLine("{0}: {1}", obj.Author, obj.Email");
}
答案 2 :(得分:2)
我使用扩展方法
public static IDataReader GetReader(this IDbConnection conn,string query, params object[] values) {
var Command=conn.CreateCommand();
var paramNames=Enumerable.Range(1,values.Length).Select(i=>string.Format("@param{0}",i)).ToArray();
Command.CommandText=string.Format(query,paramNames);
for (var i=0;i<values.Length;i++) {
var param=Command.CreateParameter();
param.ParameterName=paramNames[i];
param.Value=values[i];
Command.Parameters.Add(param);
}
return Command.ExecuteReader();
}
然后您可以在代码中使用字符串格式语法进行查询。
e.g。
Conn.GetReader("SELECT author, email FROM authors WHERE dest={0}",dest);
答案 3 :(得分:1)
获取和ORM或抽象此样板代码:
public static IDataReader ExecuteCommand(this IDbConnection dbConnection,
string query, object parameters)
{
// Left as an exercise
}
var dataReader = connection.ExecuteCommand(
"select * from Foo where Bar = @bar and Baz = @baz",
new { bar = "12332", baz = DateTime.Now });
答案 4 :(得分:0)
如果你看一下C#(Linq to SQL,Entity Framework)的标准ORM框架,你最终可能会得到这样的结论:
using (DBClasses db = new DBClasses())
{
IEnumerable<AuthorInfo> authors = from item in db.authors
where item.dest == s
select item;
}
此代码以强类型方式提取作者,您不必自己输入SQL查询,也不必管理连接/ SQL读取器。
处理数据库“老派”方式只有在您需要高性能时才有道理。
答案 5 :(得分:0)
如果需要,您可以编写纯SQL:
SQLiteCommand query = m_conn.CreateCommand();
query.CommandText = "SELECT author, email FROM authors WHERE dest='" + s + "'";
m_datareader = query.ExecuteReader();
我通常会加上这个:
DataTable T = query.ExecuteReader().Tables[0];
因为DataTable对我来说比DataReader更有用。在成功的查询中,您始终可以获得一个数据表结果。