2009-04-16 22 views
5

Estoy escribiendo un método para devolver una fila de 'activos' desde la base de datos. Contiene cadenas, ints y una matriz de bytes (esto podría ser una imagen/película/documento).Manera más eficiente para obtener una fila de datos de la base de datos en ASP.NET

Ahora, para el acceso a la mayoría de las filas, utilizo el siguiente método, que devuelve NameValueCollection, ya que es un objeto liviano, fácil de usar y para interpretar int y strings.

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

Ahora mi objetivo para este tipo de acceso a datos normalmente sería obtener un método para devolver un datarow.

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

Parece un desperdicio crear una DataTable y luego devolver su primer datarow.

¿Hay una mejor manera de hacerlo?

Estoy pensando que tal vez un diccionario de objetos que a continuación, de forma manual cada miembro de.

Sería interesante ver cómo otros han abordado esto. Sé que esto cae en el campo de la micro optimización y siempre que no devuelva DataSets para cada consulta de fila (desearía tener una libra por cada vez que lo vi en una línea de código) debería estar bien.

Dicho esto, es probable que se requiera este método para asignar consultas de acceso a datos en un lote de sitios en un cuadro.

Saludos

Steve

+1

Sólo un pequeño problema, pero la persona que llama debe llamar al método DbCommand.Dispose, no a los métodos de lectura de datos. Como la persona que llama le proporcionó el objeto dbCommand, debe reducirlo. –

Respuesta

7

¿cómo te va?

¿Hay algún motivo por el que no tenga contenedores de objetos que representen una fila en su base de datos? Crear un objeto personalizado es mucho más fácil de tratar en otros niveles de su solución. Entonces, yendo con este enfoque, hay dos soluciones muy viables para sus problemas.

Supongamos que tiene un objeto personalizado que representa un Producto en su base de datos. Se podría definir el objeto como éste:

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

Y será llenar una colección de los productos (Collection) como este:

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

en cuenta que estoy recuperar un valor a través del lector de Obtenga x donde x es el tipo que quiero recuperar de la columna. Esta es la forma recomendada por Microsoft de recuperar datos para una columna por http://msdn.microsoft.com/en-us/library/haa3afyz.aspx (segundo párrafo) porque el valor recuperado no tiene que estar encajonado en System.Object y unboxed en un tipo primitivo.

Como mencionó que este método se llamará muchas, muchas veces, en una aplicación ASP.NET, es posible que desee reconsiderar un enfoque tan genérico como este. El método que utiliza para devolver NameValueCollection es muy poco efectivo en este escenario (y podría decirse que en muchos otros escenarios). Sin mencionar que convierte cada columna de base de datos en una cadena sin tener en cuenta la Cultura del usuario actual, y Cultura es una consideración importante en una aplicación ASP.NET. Yo diría que este NameValueCollection no debería utilizarse en sus otros esfuerzos de desarrollo también. Podría seguir y seguir sobre esto, pero te guardaré mis discursos.

Por supuesto, si va a crear objetos que se asignen directamente a sus tablas, también puede consultar LINQ to SQL o ADO.NET Entity Framework. Estarás feliz de haberlo hecho.

+0

+1 porque nunca me había fijado en el lector.Métodos de Getxxx antes de ahora y ¡es un gran consejo! – BenAlabaster

2

Lo que estás demonstarting es un olor código llamado Primitive Obsession. Cree un tipo personalizado y devuélvalo desde su método de repositorio. No intente ser demasiado genérico ... terminará introduciendo esa complejidad en su código comercial porque interactuará con sus entidades utilizando un código puramente de procedimiento. Es mejor crear objetos que modelen su negocio.

Si le preocupa el exceso de código de acceso a los datos, busque un marco ORM para generarlo. No debe dejar que esta preocupación dicte un mal diseño en su capa de aplicación.

3

En términos de eficiencia de código, probablemente lo haya hecho con las menos pulsaciones de teclas, y si bien parece un desperdicio, es probablemente el más simple de mantener. Sin embargo, si usted es todo acerca de la eficiencia de sólo el hacer lo que es estrictamente necesario, puede crear una estructura/clase de peso ligero para rellenar con los datos y usar algo similar a:

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

Del mismo modo, se podría volcar los datos en de manera similar a la derecha en su colección de KVPS ...

no es tan limpia que mira por ejemplo el código original, pero no crea toda la tabla sólo para obtener la hilera ...

como ha ya se mencionó en otro post sobre el código, aunque probablemente no pasaría el comando como parámetro, creo que estaría es más probable que encapsule el comando dentro de este método, pasando solo la conexión de la base de datos y el id del activo que quería, suponiendo que no use el almacenamiento en caché, por supuesto, y vuelva a pasar la instancia de MyAsset. Esto mantiene el método lo suficientemente genérico como para poder usarlo en cualquier tipo de base de datos, suponiendo que el proceso almacenado existiera por supuesto. De esta forma, el resto de mi código está protegido de la necesidad de saber algo sobre la base de datos que no sea el tipo de base de datos que es ...y en el resto de mi aplicación, puedo hacer referencia a la información de activos usando MyAssetInstance.ID, MyAssetInstance.Name, MyAssetInstance.Description etc ...

0

Obtendrá mucho más beneficio de los datos de almacenamiento en caché que tratar de optimizar el retorno de una sola fila . Si selecciona por clave principal, es poco probable que vea una diferencia entre devolver un DataTable o un DataRow o un objeto personalizado. Esto me parece una optimización prematura. Sería más definido, pero no estoy seguro si tener una matriz de bytes en la mezcla cambia las cosas.

0

Gracias a todos los chicos de entrada. Sé que ORM es probablemente el camino a seguir y eso y el marco MVC son los siguientes en mi lista.

Para dar un poco más de detalle, el código que estoy mostrando es de la sección de ayuda en mi capa de acceso a datos que pasa la colección de valores de filas o nombres a la capa empresarial para convertirlos en objetos.

Creo que los ejemplos del código mnero0429 y balabaster me dan la dirección correcta. Use un lector de datos y obtenga los datos de esa forma de forma manual sin tener que lidiar con objetos intermediarios. Gracias por el enlace MS detallado mnero0429. Justo en la primitiva obsesión - aunque realmente creo una clase de activos adecuada en la capa empresarial;)

Voy a estar investigando el marco de la entidad ADO también.

Una vez más, gracias por el consejo: sé que el mundo seguiría girando incluso si usaba DataSet.Tables [0].Filas [0] ["bob"] o algo así, pero cuando tienes ese picor, ¿cuál es el MEJOR wat para hacerlo, es bueno tenerlo rayado?

Cuestiones relacionadas