2010-03-02 3 views
3

Я читал статью в MSDN несколько месяцев назад и недавно начал использовать следующий фрагмент кода для выполнения кода ADO.NET, но я чувствую, что это может быть плохо. Должен ли я реагировать или это вполне приемлемо?ADO.NET - плохая практика?

private void Execute(Action<SqlConnection> action) 
{ 
    SqlConnection conn = null; 
    try { 
     conn = new SqlConnection(ConnectionString); 
     conn.Open(); 
     action.Invoke(conn); 
    } finally { 
     if (conn != null && conn.State == ConnectionState.Open) { 
      try { 
       conn.Close(); 
      } catch { 
      } 
     } 
    } 
} 

public bool GetSomethingById() { 
    SomeThing aSomething = null 
    bool valid = false; 
    Execute(conn => 
    { 
     using (SqlCommand cmd = conn.CreateCommand()) { 
      cmd.CommandText = .... 
      ... 
      SqlDataReader reader = cmd.ExecuteReader(); 
      ... 
      aSomething = new SomeThing(Convert.ToString(reader["aDbField"])); 
     } 
    }); 
    return aSomething; 
} 
+0

Что делает это, что инструкция 'using' еще не выполняется, за исключением передачи в строке соединения для вас? –

ответ

0

Это приемлемо. Я создал класс SqlUtilities два года назад, который имел аналогичный метод. Вы можете сделать это еще на один шаг, если хотите.

EDIT: Не удалось найти код, но я напечатал небольшой пример (возможно, с большим количеством ошибок синтаксиса;))

SQLUtilities

public delegate T CreateMethod<T> (SqlDataReader reader); 
public static T CreateEntity<T>(string query, CreateMethod<T> createMethod, params SqlParameter[] parameters) { 
    // Open the Sql connection 
    // Create a Sql command with the query/sp and parameters 
    SqlDataReader reader = cmd.ExecuteReader(); 
    return createMethod(reader); 
    // Probably some finally statements or using-closures etc. etc. 
} 

телефонный код

private SomeThing Create(SqlDataReader reader) { 
    SomeThing something = new SomeThing(); 
    something.ID = Convert.ToIn32(reader["ID"]); 
    ... 
    return something; 
} 

public SomeThing GetSomeThingByID (int id) { 
    return SqlUtilities.CreateEntity<SomeThing> ("something_getbyid", Create, ....); 
} 

Конечно, вы могли бы se вместо лямбда-выражения вместо метода Create, и вы можете легко создать метод CreateCollection и повторно использовать существующий метод Create.

Однако, если это новый проект. Проверьте LINQ на сущности. Это намного проще и гибче, чем ADO.Net.

0

Это очень разумный подход к использованию.

Обертывая логику подключения в метод, который принимает Action<SqlConnection>, вы помогаете предотвратить дублированный код и потенциал для введенной ошибки. Поскольку мы теперь можем использовать lambdas, это становится простым и безопасным способом справиться с этой ситуацией.

+0

Спасибо за ваши взгляды. – Echilon

1

IMHO это действительно плохой опыт, поскольку вы создаете и открываете новое соединение с базой данных для каждого выполняемого вами оператора.

Почему это плохо:

  • производительность мудрым (хотя Пулы соединений помогает уменьшить потери производительности): вы должны открыть соединение, выполнить операторы, которые должны быть выполнены, и закрыть соединение, когда вы не знаю, когда будет выполнен следующий оператор.

  • но, безусловно, контекстно-зависимый. Я имею в виду: как вы будете обрабатывать транзакции? Где ваши границы транзакций? Уровень вашего приложения знает, когда транзакция должна быть запущена и зафиксирована, но вы не можете охватить несколько операторов в одной и той же транзакции sql с таким образом работы.

+0

Я собирался что-то сказать. Хотя кажется, что можно выполнить несколько операторов внутри одного действия, я вижу, что он используется для генерации результатов для очень конкретных действий, что приводит к множеству ненужных отключений/подключений. –

+3

Он не открывает и не закрывает соединение с базой данных для каждого оператора. ADO.NET использует пул соединений. Вызов 'connection.Close' ** не ** закрывает базовое соединение с базой данных, но возвращает его в пул соединений для повторного использования (http://msdn.microsoft.com/en-us/library/8xx3tyca%28VS.80 % 29.aspx). –

+0

@ Darin: вот что я говорю. Но, я семантически, это все еще неправильно. –

8

Какой смысл делать это, когда вы можете это сделать?

public SomeThing GetSomethingById(int id) 
{ 
    using (var con = new SqlConnection(ConnectionString)) 
    { 
     con.Open(); 
     using (var cmd = con.CreateCommand()) 
     { 
      // prepare command 
      using (var rdr = cmd.ExecuteReader()) 
      { 
       // read fields 
       return new SomeThing(data); 
      } 
     } 
    } 
} 

Вы можете рекламировать повторное использование кода, выполняя что-то вроде этого.

public static void ExecuteToReader(string connectionString, string commandText, IEnumerable<KeyValuePair<string, object>> parameters, Action<IDataReader> action) 
{ 
    using (var con = new SqlConnection(connectionString)) 
    { 
     con.Open(); 
     using (var cmd = con.CreateCommand()) 
     { 
      cmd.CommandText = commandText; 
      foreach (var pair in parameters) 
      { 
       var parameter = cmd.CreateParameter(); 
       parameter.ParameterName = pair.Key; 
       parameter.Value = pair.Value; 
       cmd.Parameters.Add(parameter); 
      } 
      using (var rdr = cmd.ExecuteReader()) 
      { 
       action(rdr); 
      } 
     } 
    }  
} 

Вы могли бы использовать его как это:

//At the top create an alias 
using DbParams = Dictionary<string, object>; 

ExecuteToReader(
    connectionString, 
    commandText, 
    new DbParams() { { "key1", 1 }, { "key2", 2 } }), 
    reader => 
    { 
     // ... 
     // No need to dispose 
    } 
) 
+2

+1, полностью согласовано –

+0

Что произойдет, если возникло исключение? Не ошибся ли я в том, что связь будет оставлена ​​висящей и не закрытой? – Echilon

+0

@ Echilon - Нет, оператор using для ваших целей закрывает соединение. Технически он останется открытым из-за объединения пулов. – ChaosPandion

0

Ну, на мой взгляд проверки того, что вы делаете, прежде чем через it.Something, что работает не означает, что она является лучшим и хорошая практика программирования ,Посмотрите и найдите конкретный пример и получите выгоду от его использования. Но если вы планируете использовать для больших проектов, было бы неплохо использовать такие фреймворки, как NHibernate. Потому что на его основе создано множество проектов, основанных на нем, например http://www.cuyahoga-project.org/.

Смежные вопросы