SQL в C # - почему так многословно? - PullRequest
3 голосов
/ 29 июля 2011

Я использовал postgreSQL в PHP, и это было просто: когда вы делаете запрос, вы делаете:

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

Простой.Безопасный (насколько я знаю).

Теперь я хочу сделать то же самое с SQLite в 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();

Не слишком ли это излишне?Если нет, то почему?

Из того, что я знаю, в конце концов, строка, отправляемая в базу данных, все еще является строкой, почему она должна проходить через это, а не просто вручную обрабатывать небезопасные строки?Если в 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 строк для каждого запроса?

Ответы [ 6 ]

7 голосов
/ 29 июля 2011

Параметризованные запросы являются лучшим выбором, поскольку они обычно безопасны от типа, обрабатывают любые экранированные символы, буквальное форматирование и т. Д., А также позволяют серверу / бэкэнду кэшировать скомпилированный запрос для повышения производительности.

Большинство механизмов баз данных позволяют вам выполнять как «простой старый sql», так и параметризованный запросы.

Конечно, для построения полных строк SQL требуется, чтобы вы знали точные форматы и типы данных, используемые СУБД, поскольку они всеотличается.

2 голосов
/ 29 июля 2011

Я использую метод расширения

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

Тогда вы можете просто в своем коде использовать синтаксис строкового формата для вашего запроса.

Например,

Conn.GetReader("SELECT author, email FROM authors WHERE dest={0}",dest);
2 голосов
/ 29 июля 2011

Есть несколько очень эффективных инструментов, которые помогут с этим.Поскольку у вас есть SQL, и вам не нужна сложность, разумно выбрать микро-ORM, например, «dapper»:

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");
}
1 голос
/ 29 июля 2011

Получить и 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 });
0 голосов
/ 29 июля 2011

Вы можете просто написать простой 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. При успешном запросе вы всегда получаете один результат с данными.

0 голосов
/ 29 июля 2011

Если вы посмотрите немного на стандартные ORM-фреймворки для C # ( Linq to SQL , Entity Framework ), в конечном итоге вы можете придумать что-то вроде этого:1006 *

Этот код извлекает авторов строго типизированным способом, вам не нужно вводить запросы SQL самостоятельно, а также не нужно управлять подключениями / программами чтения SQL.

Работа с базами данных«Старая школа» оправдана, только если вам нужна высокая производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...