开发者

SQL in C# - why so verbose?

I used postgreSQL in PHP, and this was simple : when you make a query, you do :

$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# :

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

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();
    }
    ~QueryResult开发者_如何学CSet()
    {
        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 ?


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.

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.


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.

e.g.

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


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:

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:

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


Get and ORM or abstract this bolierplate code:

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:

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.

Handling databases the 'old-school' way is only justified if you need high performance.


You can just write the plain SQL if you want:

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. On a sucessful query, you always get the one datatable result.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜