2009-04-16 5 views
5

Piszę metodę zwracania wiersz "aktywów" z bazy danych. Zawiera łańcuchy, int i tablicę bajtów (może to być obraz/film/dokument).Najbardziej efektywny sposób, aby uzyskać wiersz danych z DB W ASP.NET

Teraz dla większości dostępu do wiersza używam następującej metody, która zwraca wartość NameValueCollection, ponieważ jest to obiekt o niewielkiej wadze, łatwy w użyciu i rzutujący int i łańcuchy.

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

Teraz mój apporach do tego rodzaju dostępu do danych będzie zwykle uzyskać metodę zwracania 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; 
    } 

To wydaje się trochę marnować czas, aby utworzyć DataTable, a następnie zwrócić jego pierwszy datarow.

Czy jest lepszy sposób to zrobić?

Myślę, że może być Słownikiem obiektów, które następnie ręcznie rzucam każdego członka.

Byłoby interesujące zobaczyć, jak inni sobie z tym poradzili. Wiem, że ten rodzaj wpada w pole mikro optymalizacji i tak długo, jak nie zwracam zestawów danych dla każdego wiersza zapytania (chciałbym mieć funta za każdym razem, gdy widziałem to w linii kodu) powinno być w porządku.

To powiedziawszy, że ta metoda będzie prawdopodobnie wywoływana w przypadku wielu zapytań o dostęp do danych na wielu stronach w jednym pudełku.

Cheers

Steve

+1

Tylko mały numer, ale osoba wywołująca powinna wywoływać metodę DbCommand.Dispose, a nie metody odczytu danych. Ponieważ Twój program wywołujący podał obiekt dbCommand, powinien go odrzucić. –

Odpowiedz

7

jak leci?

Czy istnieje powód, dla którego nie masz kontenerów obiektów reprezentujących wiersz w bazie danych? Tworzenie niestandardowego obiektu jest łatwiejsze w obsłudze na innych poziomach rozwiązania. Tak więc, stosując to podejście, istnieją dwa bardzo realistyczne rozwiązania twoich problemów.

Załóżmy, że masz niestandardowy obiekt reprezentujący Produkt w bazie danych. Można by określić przedmiot takiego:

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

I chcesz wypełnić kolekcję produktów (kolekcja), takich jak ten:

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

Zauważ, że jestem pobierania wartości przez czytelnika Uzyskaj x gdzie x jest typem, który chcę pobrać z kolumny. Jest to zalecany przez Microsoft sposób pobierania danych dla kolumny według http://msdn.microsoft.com/en-us/library/haa3afyz.aspx (drugi akapit), ponieważ pobrana wartość nie musi być umieszczona w System.Object i rozpakowana do typu pierwotnego.

Odkąd wspomniałeś, że ta metoda będzie nazywać się wiele razy w aplikacji ASP.NET, możesz rozważyć takie ogólne podejście. Metoda użyta do zwrócenia wartości NameValueCollection jest bardzo nieskuteczna w tym scenariuszu (i prawdopodobnie w wielu innych scenariuszach). Nie wspominając o tym, że konwertujesz każdą kolumnę bazy danych na ciąg bez uwzględniania kultury użytkownika, a kultura jest ważnym czynnikiem w aplikacji ASP.NET. Twierdzę, że ta NameValueCollection nie powinna być używana w innych twoich wysiłkach na rzecz rozwoju. Mógłbym mówić o tym dalej, ale uratuję ci moje rekiny.

Oczywiście, jeśli zamierzasz tworzyć obiekty, które bezpośrednio mapują do twoich stołów, równie dobrze możesz zajrzeć do LINQ to SQL lub ADO.NET Entity Framework. Będziesz szczęśliwy, że to zrobiłeś.

+0

+1, ponieważ nigdy wcześniej nie zauważyłem metod czytania.Getxxx i jest to świetna wskazówka! – BenAlabaster

2

Co ty demonstarting to zapach kod nazywany Primitive Obsession. Utwórz niestandardowy typ i zwróć go z metody repozytorium. Nie staraj się być zbyt ogólnikowym ... po prostu w końcu wpiszesz tę złożoność w swój kod biznesowy, ponieważ będziesz interakcji z twoimi jednostkami za pomocą czysto proceduralnego kodu. Lepiej tworzyć obiekty, które modelują Twoją firmę.

Jeśli obawiasz się zbyt dużej ilości kodu dostępu do danych, zajrzyj do korzystania z frameworka ORM, aby zająć się wygenerowaniem tego dla Ciebie. Nie powinieneś pozwalać, by ta troska wskazywała zły projekt w twojej warstwie aplikacji.

3

Pod względem wydajności kodu, prawdopodobnie zrobiłeś to po najmniejszych naciśnięciach klawiszy, a jednocześnie wydaje się marnotrawstwem, jest prawdopodobnie najprostszy w utrzymaniu. Jednakże, jeśli jesteś wszystkim o skuteczności tylko to, co jest ściśle konieczne można stworzyć lekką struct/klasy, aby wypełnić z danymi i korzystania coś podobnego do:

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

Podobnie, można zrzucić danych w podobny sposób prawo do swojej kolekcji KVPS ...

to nie tak czysty, jak szuka oryginalnego kodu, ale nie tworzy całą tabelę, aby dostać się jeden wiersz ...

jak ma Wspomniano już w innym poście o zapachu z kodem, prawdopodobnie nie przekazałbym polecenia jako parametru, myślę, że byłbym bardziej prawdopodobne jest zamknięcie polecenia wewnątrz tej metody, przekazanie tylko połączenia z bazą danych i identyfikatora zasobu, którego potrzebowałem - zakładając, że nie korzystałem oczywiście z buforowania i wycofywałem instancję MyAsset. Dzięki temu metoda jest na tyle ogólna, że ​​można jej używać na dowolnym typie bazy danych - zakładając oczywiście, że przechowywany proces istniał. W ten sposób reszta mojego kodu jest chroniona przed koniecznością dowiedzenia się czegoś o bazie danych innej niż typ bazy danych ...w całej mojej aplikacji mogę odwoływać się do informacji o zasobach za pomocą MyAssetInstance.ID, MyAssetInstance.Name, MyAssetInstance.Description itp.

0

Osiągniesz więcej korzyści z buforowania danych niż próbę optymalizacji zwracania pojedynczego wiersza . Jeśli wybierasz według klucza podstawowego, jest mało prawdopodobne, że zauważysz różnicę między zwróceniem Data Data lub DataRow lub niestandardowym obiektem. To uderza mnie jako przedwczesną optymalizację. Byłbym bardziej określony, ale nie jestem pewien, czy posiadanie tablicy bajtów w miksie zmienia rzeczy.

0

Dzięki za wszystkich gości. Wiem, że ORM to prawdopodobnie droga, a ramy MVC są następne na mojej liście.

Aby podać nieco więcej szczegółów, kod, który wyświetlam, pochodzi z sekcji pomocy w mojej warstwie dostępu do danych, która następnie przekazuje kolekcję wiersza lub kolekcji nazw do warstwy biznesowej, aby zamienić się w obiekty.

Myślę, że przykłady kodu mnero0429 i balabaster dają mi właściwy kierunek. Użyj datareadera i ręcznie wyślij dane w ten sposób, nie naruszając przy tym obiektów zabezpieczających. Dzięki za szczegółowy link MS mnero0429. Bądź uczciwy w stosunku do pierwotnej obsesji - tak naprawdę robię z tego odpowiednią klasę aktywów w warstwie biznesowej;)

Zajmę się także strukturą podmiotu ADO.

Jeszcze raz dziękuję za poradę - wiem, że świat będzie się obracał, nawet jeśli używałbym DataSet.Tables [0].Rzędy [0] ["bob"] lub niektóre z nich, ale gdy pojawi się ten świąd - co jest NAJLEPSZE do tego, fajnie jest go zadrapać!

Powiązane problemy