繁体   English   中英

使用IEnumerable是否有任何陷阱 <T> 返回SQL数据的类型?

[英]Are there any pitfalls to using an IEnumerable<T> return type for SQL data?

我的问题是关于SQL连接状态,负载等基于以下代码:

public IEnumberable<MyType> GetMyTypeObjects()
{
  string cmdTxt = "select * from MyObjectTable";

  using(SqlConnection conn = new SqlConnection(connString))
  {
    using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
    {
      conn.Open();
      using(SqlDataReader reader = cmd.ExecuteReader())
      {
         while(reader.Read())
         {
            yield return Mapper.MapTo<MyType>(reader);
         }
       }
    }
  }
  yield break;
}

我可以看到这可能是一个问题,如果有许多进程在IEnumerable对象的迭代之间运行类似的代码并且执行时间很长,因为连接将打开更长时间等等。但是,这似乎也可能会降低CPU使用率在SQL服务器上,因为它只在使用IEnumerable对象时返回数据。 它还降低了客户端上的内存使用量,因为客户端只需在其工作时加载一个MyType实例,而不是加载所有出现的MyType(通过迭代整个DataReader并返回List或其他内容)。

  • 您是否有任何实例可以想到您不希望以这种方式使用IEnumerable,或者您认为它完全适合的任何实例?

  • 这会给SQL服务器带来什么样的负载?

  • 这是你在自己的代码中使用的东西(除非提及NHibernate,Subsonic等)吗?

  • -

这不是我要遵循的模式。 我不会像在锁定时那样担心服务器上的负载。 遵循这种模式将数据检索过程集成到您的业务逻辑流程中,这似乎是一个全面解决问题的方法; 你不知道在迭代方面会发生什么,而你正在插入它。 一次性检索您的数据,然后在关闭阅读器后允许客户端代码对其进行枚举。

我建议不要进行预优化。 在许多情况下,将汇集连接。

我也不希望SQL Server上的负载有任何差异 - 查询已经编译完毕,并且将会运行。

我不会使用它,因为它隐藏了正在发生的事情,它可能会在没有适当处置的情况下留下数据库连接。

读取超过最后一条记录后,将关闭连接对象,如果在此之前停止读取,则不会处理连接对象。 例如,如果您知道结果中总是有10条记录,并且只有一个循环从枚举器中读取这10条记录而没有使第11条读取调用超出最后一项,则连接未正确关闭。 此外,如果您只想使用部分结果,则无法在不读取其余记录的情况下关闭连接。

即使你正确使用它们,即使是枚举器的内置扩展也可能导致这种情况:

foreach (MyType item in GetMyTypeObjects().Take(10)) {
   ...
}

我担心的是你完全受到客户代码的怜悯。

您已经提到调用代码可能会将连接打开的时间超过严格必要的时间,但也有可能永远不会允许关闭/处置对象。

只要客户端代码使用foreachusing etc或显式调用枚举器的Dispose方法,那么你很好,但没有什么可以阻止它做这样的事情:

var e = GetMyTypeObjects().GetEnumerator();
e.MoveNext();    // open the connection etc

// forget about the enumerator and go away and do something else
// now the reader, command and connection won't be closed/disposed
// until the GC kicks in and calls their finalisers

暂无
暂无

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

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