简体   繁体   English

C#中的SQL - 为什么这么详细?

[英]SQL in C# - why so verbose?

I used postgreSQL in PHP, and this was simple : when you make a query, you do : 我在PHP中使用了postgreSQL,这很简单:当你进行查询时,你会这样做:

$result = pg_query($conn, "SELECT author, email FROM authors WHERE dest='" + pg_escape_string($s) + "'");

Simple. 简单。 Secure (as far as I know). 安全(据我所知)。

Now I want to do the same thing with SQLite in C# : 现在我想在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();

Is it not a bit of an overkill ? 是不是有点矫枉过正? If not, why ? 如果没有,为什么?

From what I know, in the end, the string sent to the database is still a string, why should it go trough this instead of just manually sanitizing unsafe strings ? 据我所知,最后,发送到数据库的字符串仍然是一个字符串,为什么要通过这个而不是仅手动清理不安全的字符串? If in ASP .NET to print some unsafe text to HTML is it also 如果在ASP .NET中打印一些不安全的文本也是HTML

htmlAdd.Text("<div>@param1</div>");
htmlAdd.Parameters.Add("@param1").Value = unsafeUsername;

?

I wanted to do this class : 我想上这堂课:

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;
}

But now I have to change the method in : 但现在我必须改变方法:

public QueryResultSet(SQLiteConnection conn, string queryText, Dictionary<string,string> params)

That will cause the code before the method and into it to double its size. 这将导致方法之前的代码进入它的大小加倍。

Any standard way to do it ? 有什么标准方法吗? If this class isn't a good idea, how to avoid having to do 10 lines for each request ? 如果这个类不是一个好主意,如何避免为每个请求做10行?

Parameterised queries are the better choice as they're normally type safe, handle any escaping, literal formatting, etc for you, as well as allowing the server/backend to cache the compiled query for better performance. 参数化查询是更好的选择,因为它们通常是类型安全的,为您处理任何转义,文字格式等,以及允许服务器/后端缓存已编译的查询以获得更好的性能。

Most database engines will allow you to do both "plain old sql" and parameterised queries. 大多数数据库引擎都允许您同时执行“普通旧sql”和参数化查询。

Of course, building up full SQL strings requires you to know the exact formats and data types used by the RDBMS as they all differ. 当然,构建完整的SQL字符串需要您了解RDBMS使用的确切格式和数据类型,因为它们都有所不同。

There are some very effective tools to help with this. 有一些非常有效的工具可以帮助解决这个问题。 Since you have SQL and don't need complexity, a micro-ORM such as "dapper" is a reasonable choice: 既然你有SQL并且不需要复杂性,那么像“dapper”这样的微ORM是一个合理的选择:

var result=conn.Query<Author>("SELECT author, email FROM authors WHERE dest=@s",
    new {s});

or if you want to use dynamic instead of strong-typing: 或者如果你想使用dynamic而不是强类型:

var result=conn.Query("SELECT author, email FROM authors WHERE dest=@s",new {s});

Not so bad now? 现在还不错吗? You could then consume that via something like: 然后你可以通过以下方式消费:

foreach(var obj in result) {
    Console.WriteLine("{0}: {1}", obj.Author, obj.Email");
}

I use an extension method 我使用扩展方法

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();
}

Then you can just in your code use the string format syntax for your query. 然后,您可以在代码中使用字符串格式语法进行查询。

eg 例如

Conn.GetReader("SELECT author, email FROM authors WHERE dest={0}",dest);

Get and ORM or abstract this bolierplate code: 获取和ORM或抽象这个bolierplate代码:

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

If you look a bit into the standard ORM frameworks for C# ( Linq to SQL , Entity Framework ), you could eventually come up with something like this: 如果你看一下C#( Linq to SQLEntity Framework )的标准ORM框架,你最终可能会得到这样的东西:

using (DBClasses db = new DBClasses())
{
    IEnumerable<AuthorInfo> authors = from item in db.authors
                                      where item.dest == s
                                      select item;
}

This code extracts the authors in a strongly-typed manner, you won't have to type in your SQL queries yourself, nor you have to manage the connections / SQL readers. 此代码以强类型方式提取作者,您不必自己键入SQL查询,也不必管理连接/ SQL读取器。

Handling databases the 'old-school' way is only justified if you need high performance. 处理数据库“老派”方式只有在您需要高性能时才有道理。

You can just write the plain SQL if you want: 如果需要,您可以编写纯SQL:

SQLiteCommand query = m_conn.CreateCommand();
query.CommandText = "SELECT author, email FROM authors WHERE dest='" + s + "'";
m_datareader = query.ExecuteReader();

I generally add this: 我通常添加这个:

DataTable T = query.ExecuteReader().Tables[0];

As a DataTable is more useful to me than a DataReader. 因为DataTable对我来说比DataReader更有用。 On a sucessful query, you always get the one datatable result. 在成功的查询中,您始终可以获得一个数据表结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM