2009-04-16 123 views
5

我正在编写一个方法来从数据库中返回“资产”行。它包含字符串,整数和一个字节数组(这可能是一个图像/电影/文档)。从ASP.NET中的数据库获取一行数据的最有效方法

现在,对于大多数行访问,我使用下面的方法返回一个NameValueCollection,因为它是一个轻量级的对象,易于使用和投射int和字符串。

 public static NameValueCollection ReturnNameValueCollection(Database db, DbCommand dbCommand) 
    { 

     var nvc = new NameValueCollection(); 

     using (IDataReader dr = db.ExecuteReader(dbCommand)) 
     { 
      if (dr != null) 
      { 
       while (dr.Read()) 
       { 
        for (int count = 0; count < dr.FieldCount; count++) 
        { 
         nvc[dr.GetName(count)] = dr.GetValue(count).ToString(); 
        } 
       } 
      } 
     } 

     dbCommand.Dispose(); 
     return nvc.Count != 0 ? nvc : null; 
    } 

现在我对这种数据访问的支持通常是获得返回数据行的方法。

 public static DataRow ReturnDataRow(Database db, DbCommand dbCommand) 
    { 
     var dt = new DataTable(); 

     using (IDataReader dr = db.ExecuteReader(dbCommand)) 
      if (dr != null) dt.Load(dr); 

     dbCommand.Dispose(); 
     return dt.Rows.Count != 0 ? dt.Rows[0] : null; 
    } 

创建一个DataTable然后返回它的第一个datarow似乎有点浪费。

有没有更好的方法来做到这一点?

我想也许是一个对象的字典,然后我手动投的每个成员。

看到别人如何解决这个问题会很有趣。我知道这种情况属于微型优化领域,只要我没有为每一行查询返回DataSet(希望每次在代码行中看到它都有一磅),它应该没问题。

也就是说这种方法很可能被要求在一个盒子上的所有站点上分配数据访问查询。

干杯

史蒂夫

+1

只是一个小问题,但调用者应该调用DbCommand.Dispose方法,而不是您的数据读取方法。由于您的调用者提供了dbCommand对象,因此应该引用它。 – 2009-04-16 19:55:31

回答

7

最近怎么样?

是否有一个原因你没有对象容器代表数据库中的一排?创建自定义对象在解决方案的其他层中更容易处理。所以,采用这种方法,有两个非常可行的解决方案来解决您的问题。

假设您有一个代表数据库中的产品的自定义对象。你会这样定义对象:

public class Product { 
    public int ProductID { get; set; } 
    public string Name { get; set; } 
    public byte[] Image { get; set; } 
} 

而且你会填补的产品(集合)这样的集合:

var collection = new Collection<Product>(); 

using (var reader = command.ExecuteReader()) { 
    while (reader.Read()) { 
     var product = new Product(); 

     int ordinal = reader.GetOrdinal("ProductID"); 
     if (!reader.IsDBNull(ordinal) { 
      product.ProductID = reader.GetInt32(ordinal); 
     } 

     ordinal = reader.GetOrdinal("Name"); 
     if (!reader.IsDBNull(ordinal)) { 
      product.Name = reader.GetString(ordinal); 
     } 

     ordinal = reader.GetOrdinal("Image"); 
     if (!reader.IsDBNull(ordinal)) { 
      var sqlBytes = reader.GetSqlBytes(ordinal); 
      product.Image = sqlBytes.Value; 
     } 

     collection.Add(product); 
    } 
} 

注意到,我通过读者的检索值获取 x其中 x是我想要从列中检索的类型。这是微软推荐的根据http://msdn.microsoft.com/en-us/library/haa3afyz.aspx(第二段)检索列的数据的方式,因为检索到的值不必装箱到System.Object中并拆箱为原始类型。

既然你提到这个方法会被调用很多次,在ASP.NET应用程序,你可能要重新考虑这样一个通用的方法,因为这一点。在这种情况下(并且可以说在许多其他情况下),用于返回 NameValueCollection的方法非常不流畅。更不用说,您将每个数据库列转换为字符串而不考虑当前用户的文化,文化是ASP.NET应用程序中的一个重要考虑因素。我认为这个 NameValueCollection不应该用于你的其他开发工作。我可以继续谈论这件事,但我会救你我的咆哮。

当然,如果您打算创建直接映射到表格的对象,那么最好查看LINQ to SQLADO.NET Entity Framework。你会很高兴你做到了。

+0

+1因为我从来没有注意到reader.Getxxx方法现在,这是一个伟大的提示! – BenAlabaster 2009-04-16 18:34:37

2

什么你demonstarting一个名为Primitive Obsession代码味道。创建一个自定义类型并从您的存储库方法返回。不要试图过于通用......你最终会将这种复杂性推到业务代码中,因为你会使用纯程序代码与你的实体进行交互。更好地创建模型化您的业务的对象。

如果您关心的是过多的数据访问代码,请着手使用ORM框架来为您生成此代码。你不应该让这个问题在你的应用层中指定糟糕的设计。

3

就代码效率而言,您可能以最少的击键次数完成了它,虽然看起来很浪费,但可能是最简单的维护。但是,如果你所有关于只有这样做,你可以创造什么是绝对必要的轻​​量级结构/类来用数据,并使用类似的东西来效率:

public class MyAsset 
{ 
    public int ID; 
    public string Name; 
    public string Description; 
} 

public MyAsset GetAsset(IDBConnection con, Int AssetId) 
{ 
    using (var cmd = con.CreateCommand("sp_GetAsset")) 
    { 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.Add(cmd.CreateParameter("AssetID")); 
     using(IDataReader dr = cmd.ExecuteReader()) 
     { 
      if (!dr.Read()) return null; 

      return new MyAsset() { 
       ID = dr.GetInt32(0), 
       Name = dr.GetString(1), 
       Description = dr.GetString(2) 
      }; 
     } 
    } 
} 

同样,你可以转储数据类似的方式到您的权利KVPs的集合......

这不是很干净地看着你的原代码,但它不会创建整个表只是为了让单列...

由于具有在另一篇关于代码味道的文章中提到过,我可能不会将命令作为参数传递,我想我会这样做更可能将此命令封装在此方法中,只传递数据库连接和我想要的资产的ID - 假设当然没有使用缓存,并传回MyAsset实例。这保持了方法的通用性,可以用于任何数据库类型 - 假设存储的proc当然存在。通过这种方式,我的代码的其余部分不需要知道数据库的任何内容,而不需要知道数据库的类型。并在我的应用程序的其余部分中,我可以使用MyAssetInstance.ID,MyAssetInstance.Name,MyAssetInstance.Description等参考资产信息...

0

与试图优化返回单行相比,您将从缓存数据中获得更多好处。如果您通过主键选择,那么您不太可能会看到返回DataTable或DataRow或自定义对象之间的任何区别。这让我觉得不成熟的优化。我会更确定,但我不确定是否在混音中有一个字节数组会改变事情。

0

感谢所有的输入人。我知道ORM可能是要走的路,而MVC框架就在我的列表中。

为了让更多的细节,我展示的代码是从我的数据访问层的助手部分,然后通过该行或名称值集合业务层变成对象。

我觉得mnero0429和balabaster代码示例给我正确的方向。使用数据读取器并手动获取数据,而不会混淆中间对象。感谢您的详细MS链接mnero0429。博览会上的灵长类动物的痴迷 - 尽管我确实做适当的资产类别出它在业务层)

我会寻找到ADO实体框架了。

再次感谢您的意见 - 我知道这个世界将继续,即使我用DataSet.Tables [0]转向。行[0] [“bob”]或其他类似的东西,但是当你得到那个痒时 - 最好的办法是做它,它很高兴能够抓住它!

相关问题