2010-03-02 47 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'语句还没有做什么? – 2010-03-02 20:48:33

回答

0

这是可以接受的。两年前,我创建了一个类似的方法的SqlUtilities类。如果你喜欢,你可以进一步。

编辑:找不到代码,但是我输入了一个小例子(可能有许多语法错误;))

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

当然,你可以ü选择一个lambda表达式而不是Create方法,并且可以轻松地创建一个CreateCollection方法并重用现有的Create方法。

但是,如果这是一个新的项目。查看LINQ to实体。比ADO.Net更加容易和灵活。

0

这是用一个非常合理的做法。

通过包装你的逻辑连接成需要一个Action<SqlConnection>,你帮助防止重复码和引入误差的可能性的方法。因为我们现在可以使用lambda表达式,所以这成为处理这种情况的一种简单,安全的方式。

+0

感谢您的意见。 – Echilon 2010-03-02 20:28:56

1

恕我直言,这的确是一个不好的做法,因为你创建和打开为您执行每一个语句的新的数据库连接。

为什么这样做不好:

  • 性能明智的(虽然连接池有助于减少对性能的影响):你应该打开你的连接,执行已被执行的语句,你什么时候关闭连接不知道下一个语句何时会被执行。

  • 但肯定上下文明智的。我的意思是:你将如何处理交易?你的交易界限在哪里?您的应用程序层知道什么时候必须启动并提交事务,但您无法使用这种工作方式将多个语句跨越到同一个sql事务中。

+0

我想说点什么来达到这个效果。虽然看起来可以在单个操作中执行多个语句,但我可以看到它被用于为特定操作生成结果,导致大量不必要的断开/连接行为。 – 2010-03-02 18:29:36

+3

他没有打开和关闭每个语句的数据库连接。 ADO.NET使用连接池。调用'connection.Close' **不会关闭底层数据库连接,但会将其返回到连接池以供重用(http://msdn.microsoft.com/zh-cn/library/8xx3tyca%28VS.80 %29.aspx)。 – 2010-03-02 18:31:00

+0

@Darin:这就是我要说的。但是,从语义上讲,它仍然是错误的。 – 2010-03-02 18:43:54

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,完全同意 – 2010-03-02 18:36:39

+0

如果发生异常,会发生什么情况?我认为连接会被挂起而没有关闭会错误吗? – Echilon 2010-03-02 20:30:48

+0

@Echilon - 不,使用声明将为您的目的关闭连接。从技术上讲,它会保持开放,因为连接池。 – ChaosPandion 2010-03-02 20:38:51

0

嗯,在我看来你检查之前通过工作并不意味着它会it.Something做什么是最好的,良好的编程习惯。看看并找到一个使用它的具体例子和好处。但是如果你正在考虑使用大项目,那么使用像NHibernate这样的框架会很好。因为有很多项目甚至基于它开发的框架,比如http://www.cuyahoga-project.org/