Dodawanie dodatkowych kolumn tabeli DataTable (VB)
Autor : Scott Mitchell
Korzystając z Kreatora tableAdapter do utworzenia typu zestawu danych, odpowiednia tabela DataTable zawiera kolumny zwracane przez główne zapytanie bazy danych. Istnieją jednak sytuacje, w których tabela DataTable musi zawierać dodatkowe kolumny. W tym samouczku dowiesz się, dlaczego procedury składowane są zalecane, gdy potrzebujemy dodatkowych kolumn DataTable.
Wprowadzenie
Podczas dodawania elementu TableAdapter do typu zestawu danych odpowiedni schemat elementu DataTable jest określany przez główne zapytanie TableAdapter. Jeśli na przykład główne zapytanie zwraca pola danych A, B i C, tabela DataTable będzie zawierać trzy odpowiadające im kolumny o nazwach A, B i C. Oprócz zapytania głównego funkcja TableAdapter może zawierać dodatkowe zapytania, które zwracają, być może, podzbiór danych na podstawie określonego parametru. Na przykład oprócz ProductsTableAdapter
zapytania głównego, które zwraca informacje o wszystkich produktach, zawiera również metody, takie jak GetProductsByCategoryID(categoryID)
i GetProductByProductID(productID)
, które zwracają określone informacje o produkcie na podstawie podanego parametru.
Model schematu tabeli DataTable odzwierciedla główne zapytanie tableAdapter, jeśli wszystkie metody tableAdapter zwracają te same lub mniej pól danych niż określone w zapytaniu głównym. Jeśli metoda TableAdapter musi zwrócić dodatkowe pola danych, należy odpowiednio rozwinąć schemat tabeli DataTable. W samouczku Master/Detail Using a Bulleted List of Master Records with a Details DataList (Lista punktowana rekordów głównych) dodaliśmy metodę , CategoriesTableAdapter
CategoryID
CategoryName
i Description
pola danych zdefiniowane w zapytaniu głównym oraz NumberOfProducts
dodatkowe pole danych, które zgłosiło liczbę produktów skojarzonych z każdą kategorią. Ręcznie dodaliśmy nową kolumnę do CategoriesDataTable
obiektu , aby przechwycić NumberOfProducts
wartość pola danych z tej nowej metody.
Zgodnie z opisem w samouczku Dotyczącym przekazywania plików należy bardzo ostrożnie stosować metody TableAdapters, które używają instrukcji AD-hoc SQL i mają metody, których pola danych nie są dokładnie zgodne z głównym zapytaniem. Jeśli kreator konfiguracji tableAdapter zostanie uruchomiony ponownie, zaktualizuje wszystkie metody tableAdapter, tak aby ich lista pól danych była zgodna z głównym zapytaniem. W związku z tym wszystkie metody z dostosowanymi listami kolumn zostaną przywrócone do głównej listy kolumn zapytania i nie będą zwracać oczekiwanych danych. Ten problem nie występuje podczas korzystania z procedur składowanych.
W tym samouczku omówimy sposób rozszerzania schematu tabeli DataTable w celu uwzględnienia dodatkowych kolumn. Ze względu na kruchość elementu TableAdapter podczas korzystania z instrukcji AD-hoc SQL w tym samouczku będziemy używać procedur składowanych. Zapoznaj się z samouczkami Creating New Stored Procedures for the Typed DataSet s TableAdapters and Using Existing Stored Procedures for the Typed DataSet s TableAdapters tutorials (Tworzenie nowych procedur składowanych dla typów elementów TableAdapter) i Using Existing Stored Procedures for the Typed DataSet s TableAdapers (Używanie istniejących procedur składowanych dla typed DataSet tableAdapers ), aby uzyskać więcej informacji na temat konfigurowania klasy TableAdapter do używania procedur składowanych.
Krok 1. DodawaniePriceQuartile
kolumny do elementuProductsDataTable
W samouczku Creating New Stored Procedures for the Typed DataSet s TableAdapters (Tworzenie nowych procedur składowanych dla typowanych elementów TableAdapters zestawu danych ) utworzyliśmy typowy zestaw danych o nazwie NorthwindWithSprocs
. Ten zestaw danych zawiera obecnie dwie tabele Danych: ProductsDataTable
i EmployeesDataTable
. Element ProductsTableAdapter
ma następujące trzy metody:
GetProducts
— główne zapytanie, które zwraca wszystkie rekordy zProducts
tabeliGetProductsByCategoryID(categoryID)
— zwraca wszystkie produkty o określonym identyfikatorze categoryID.GetProductByProductID(productID)
— zwraca określony produkt o określonym identyfikatorze productID.
Główne zapytanie i dwie dodatkowe metody zwracają ten sam zestaw pól danych, a mianowicie wszystkie kolumny z Products
tabeli. Nie ma skorelowanych podzapytania ani JOIN
ściągania powiązanych danych z Categories
tabel lub Suppliers
. W związku z tym obiekt ProductsDataTable
ma odpowiednią kolumnę dla każdego pola w Products
tabeli.
Na potrzeby tego samouczka dodajmy metodę do ProductsTableAdapter
nazwy GetProductsWithPriceQuartile
, która zwraca wszystkie produkty. Oprócz standardowych pól danych produktu będzie również zawierać PriceQuartile
pole danych, GetProductsWithPriceQuartile
które wskazuje, w którym kwartylu cena produktu spada. Na przykład te produkty, których ceny należą do najdroższych 25%, będą miały PriceQuartile
wartość 1, podczas gdy te, których ceny spadną w dolnej 25%, będą miały wartość 4. Zanim jednak zaczniemy martwić się o utworzenie procedury składowanej w celu zwrócenia tych informacji, najpierw musimy zaktualizować ProductsDataTable
element , aby uwzględnić kolumnę do przechowywania PriceQuartile
wyników podczas używania GetProductsWithPriceQuartile
metody.
Otwórz zestaw NorthwindWithSprocs
danych i kliknij prawym przyciskiem myszy element ProductsDataTable
. Wybierz pozycję Dodaj z menu kontekstowego, a następnie wybierz pozycję Kolumna.
Rysunek 1. Dodawanie nowej kolumny do (ProductsDataTable
kliknij, aby wyświetlić obraz pełnowymiarowy)
Spowoduje to dodanie nowej kolumny do tabeli Danych o nazwie Column1 typu System.String
. Musimy zaktualizować nazwę tej kolumny na PriceQuartile i jej typ, System.Int32
ponieważ będzie ona używana do przechowywania liczby z zakresu od 1 do 4. Wybierz nowo dodaną kolumnę w obiekcie ProductsDataTable
i z okno Właściwości ustaw Name
właściwość na PriceQuartile, a DataType
właściwość na System.Int32
.
Rysunek 2. Ustawianie właściwości i DataType
nowych kolumn Name
(kliknij, aby wyświetlić obraz pełnowymiarowy)
Jak pokazano na rysunku 2, istnieją dodatkowe właściwości, które można ustawić, takie jak to, czy wartości w kolumnie muszą być unikatowe, jeśli kolumna jest kolumną automatycznego zwiększania, czy wartości bazy danych NULL
są dozwolone itd. Pozostaw te wartości ustawione na wartości domyślne.
Krok 2. TworzenieGetProductsWithPriceQuartile
metody
Teraz, gdy element ProductsDataTable
został zaktualizowany w celu uwzględnienia PriceQuartile
kolumny, możemy przystąpić do tworzenia GetProductsWithPriceQuartile
metody. Zacznij od kliknięcia prawym przyciskiem myszy kontrolki TableAdapter i wybrania pozycji Dodaj zapytanie z menu kontekstowego. Spowoduje to wyświetlenie kreatora konfiguracji zapytań TableAdapter, który najpierw monituje nas o to, czy chcemy użyć instrukcji AD-hoc SQL, czy nowej lub istniejącej procedury składowanej. Ponieważ nie mamy jeszcze procedury składowanej, która zwraca dane kwartylu cen, pozwólmy usłudze TableAdapter utworzyć dla nas tę procedurę składowaną. Wybierz opcję Utwórz nową procedurę składowaną, a następnie kliknij przycisk Dalej.
Rysunek 3. Poinstruowanie Kreatora tableAdapter o utworzeniu procedury składowanej dla nas (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Na kolejnym ekranie pokazanym na rysunku 4 kreator pyta nas, jakiego typu zapytanie ma zostać dodane. GetProductsWithPriceQuartile
Ponieważ metoda zwróci wszystkie kolumny i rekordy z Products
tabeli, wybierz opcję SELECT, która zwraca wiersze, a następnie kliknij przycisk Dalej.
Rysunek 4. Zapytanie będzie instrukcją zwracającą SELECT
wiele wierszy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Następnie zostanie wyświetlony monit o SELECT
zapytanie. Wprowadź następujące zapytanie w kreatorze:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued,
NTILE(4) OVER (ORDER BY UnitPrice DESC) as PriceQuartile
FROM Products
Powyższe zapytanie używa nowej NTILE
funkcji SQL Server 2005, aby podzielić wyniki na cztery grupy, w których grupy są określane według UnitPrice
wartości posortowanych w kolejności malejącej.
Niestety konstruktor zapytań nie wie, jak przeanalizować OVER
słowo kluczowe i wyświetli błąd podczas analizowania powyższego zapytania. W związku z tym wprowadź powyższe zapytanie bezpośrednio w polu tekstowym w kreatorze bez użycia konstruktora zapytań.
Uwaga
Aby uzyskać więcej informacji na temat FUNKCJI NTILE i SQL Server 2005 innych funkcji klasyfikacji, zobacz ROW_NUMBER (Transact-SQL) i sekcję Funkcje klasyfikacji w SQL Server 2005 Książki online.
Po wprowadzeniu zapytania i kliknięciu SELECT
przycisku Dalej kreator poprosi nas o podanie nazwy procedury składowanej, która zostanie utworzona. Nadaj nowej procedurze Products_SelectWithPriceQuartile
składowanej nazwę i kliknij przycisk Dalej.
Rysunek 5. Nadaj procedurze Products_SelectWithPriceQuartile
składowanej nazwę (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Na koniec zostanie wyświetlony monit o nadenie nazwy metod TableAdapter. Pozostaw zaznaczone pola wyboru Fill a DataTable (Wypełnij tabelę danych) i Return a DataTable (Zwracanie tabeli danych) oraz nadaj metodom FillWithPriceQuartile
nazwę i GetProductsWithPriceQuartile
.
Rysunek 6. Nadaj metodom metody TableAdapter i kliknij przycisk Zakończ (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po określeniu SELECT
zapytania oraz procedurze składowanej i metodach TableAdapter o nazwie kliknij przycisk Zakończ, aby ukończyć pracę kreatora. W tym momencie może zostać wyświetlone ostrzeżenie lub dwa z kreatora z informacją, że OVER
konstrukcja lub instrukcja SQL nie jest obsługiwana. Te ostrzeżenia można zignorować.
Po ukończeniu pracy kreatora narzędzie TableAdapter powinno zawierać FillWithPriceQuartile
metody i GetProductsWithPriceQuartile
, a baza danych powinna zawierać procedurę składowaną o nazwie Products_SelectWithPriceQuartile
. Poświęć chwilę, aby sprawdzić, czy obiekt TableAdapter rzeczywiście zawiera tę nową metodę i że procedura składowana została poprawnie dodana do bazy danych. Jeśli podczas sprawdzania bazy danych nie widzisz procedury składowanej, spróbuj kliknąć prawym przyciskiem myszy folder Procedury składowane i wybrać polecenie Odśwież.
Rysunek 7. Sprawdzanie, czy nowa metoda została dodana do klasy TableAdapter
Rysunek 8. Upewnij się, że baza danych zawiera procedurę Products_SelectWithPriceQuartile
składowaną (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Uwaga
Jedną z zalet korzystania z procedur składowanych zamiast instrukcji ad hoc SQL jest to, że ponowne uruchomienie kreatora konfiguracji tableAdapter nie spowoduje zmodyfikowania list kolumn procedur składowanych. Sprawdź to, klikając prawym przyciskiem myszy tabelę TableAdapter, wybierając opcję Konfiguruj z menu kontekstowego, aby uruchomić kreatora, a następnie klikając przycisk Zakończ, aby go ukończyć. Następnie przejdź do bazy danych i wyświetl procedurę składowaną Products_SelectWithPriceQuartile
. Zwróć uwagę, że lista kolumn nie została zmodyfikowana. Gdyby używaliśmy instrukcji AD-hoc SQL, ponownie uruchomiłby kreatora konfiguracji tableAdapter, aby przywrócić listę kolumn kwerendy, aby była zgodna z główną listą kolumn zapytania, usuwając w ten sposób instrukcję NTILE z zapytania używanego przez metodę GetProductsWithPriceQuartile
.
Po wywołaniu metody warstwy GetProductsWithPriceQuartile
dostępu do danych metoda TableAdapter wykonuje procedurę Products_SelectWithPriceQuartile
składowaną i dodaje wiersz do ProductsDataTable
obiektu dla każdego zwróconego rekordu. Pola danych zwracane przez procedurę składowaną są mapowane na ProductsDataTable
kolumny s. Ponieważ z procedury składowanej jest PriceQuartile
zwracane pole danych, jego wartość jest przypisywana do ProductsDataTable
kolumny s PriceQuartile
.
Dla tych metod TableAdapter, których zapytania nie zwracają PriceQuartile
pola danych, PriceQuartile
wartość kolumny jest wartością określoną przez jego DefaultValue
właściwość. Jak pokazano na rysunku 2, ta wartość jest ustawiona na DBNull
wartość , wartość domyślna. Jeśli wolisz inną wartość domyślną, po prostu ustaw DefaultValue
odpowiednio właściwość. Upewnij się, że wartość jest prawidłowa DefaultValue
, biorąc pod uwagę kolumny DataType
(tj System.Int32
. dla kolumny PriceQuartile
).
Na tym etapie wykonaliśmy kroki niezbędne do dodania dodatkowej kolumny do tabeli DataTable. Aby sprawdzić, czy ta dodatkowa kolumna działa zgodnie z oczekiwaniami, utwórzmy stronę ASP.NET, która wyświetla nazwę, cenę i kwartyl każdego produktu. Zanim to zrobimy, najpierw musimy zaktualizować warstwę logiki biznesowej, aby uwzględnić metodę, która wywołuje metodę dal w dół do metody DAL GetProductsWithPriceQuartile
. Następnie zaktualizujemy BLL w kroku 3, a następnie utworzymy stronę ASP.NET w kroku 4.
Krok 3. Rozszerzanie warstwy logiki biznesowej
Przed użyciem nowej GetProductsWithPriceQuartile
metody z warstwy prezentacji należy najpierw dodać odpowiednią metodę do BLL. ProductsBLLWithSprocs
Otwórz plik klasy i dodaj następujący kod:
<System.ComponentModel.DataObjectMethodAttribute_
(System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsWithPriceQuartile() As NorthwindWithSprocs.ProductsDataTable
Return Adapter.GetProductsWithPriceQuartile()
End Function
Podobnie jak inne metody pobierania danych w ProductsBLLWithSprocs
metodzie , GetProductsWithPriceQuartile
metoda po prostu wywołuje odpowiednią GetProductsWithPriceQuartile
metodę DAL i zwraca jej wyniki.
Krok 4. Wyświetlanie informacji kwartylu cen na stronie internetowej ASP.NET
Po zakończeniu dodawania BLL możemy utworzyć stronę ASP.NET, która pokazuje kwartyl cen dla każdego produktu. AddingColumns.aspx
Otwórz stronę w folderze AdvancedDAL
i przeciągnij kontrolkę GridView z przybornika do Projektant, ustawiając jej ID
właściwość na Products
. Z tagu inteligentnego GridView powiąż go z nowym obiektem ObjectDataSource o nazwie ProductsDataSource
. Skonfiguruj obiekt ObjectDataSource do używania ProductsBLLWithSprocs
metody s GetProductsWithPriceQuartile
klasy. Ponieważ będzie to siatka tylko do odczytu, ustaw listy rozwijane na kartach UPDATE, INSERT i DELETE na wartość (Brak).
Rysunek 9. Konfigurowanie obiektu ObjectDataSource do używania ProductsBLLWithSprocs
klasy (kliknij, aby wyświetlić obraz pełnowymiarowy)
Rysunek 10. Pobieranie informacji o produkcie GetProductsWithPriceQuartile
z metody (kliknij, aby wyświetlić obraz pełnowymiarowy)
Po ukończeniu pracy kreatora Konfigurowanie źródła danych program Visual Studio automatycznie doda pole BoundField lub CheckBoxField do kontrolki GridView dla każdego pola danych zwracanego przez metodę . Jedno z tych pól danych to PriceQuartile
, czyli kolumna dodana do ProductsDataTable
kroku 1.
Edytuj pola kontrolki GridView, usuwając wszystkie ProductName
pola , UnitPrice
i PriceQuartile
BoundFields. Skonfiguruj pole UnitPrice
BoundField, aby sformatować jego wartość jako walutę i odpowiednio UnitPrice
wyrównać do środka i PriceQuartile
pola BoundFields. Na koniec zaktualizuj pozostałe właściwości BoundFields HeaderText
odpowiednio do właściwości Product, Price i Price Quartile. Zaznacz również pole wyboru Włącz sortowanie z tagu inteligentnego GridView.
Po tych modyfikacjach znaczniki deklaratywne gridView i ObjectDataSource powinny wyglądać następująco:
<asp:GridView ID="Products" runat="server" AllowSorting="True"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ProductsDataSource">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:BoundField DataField="PriceQuartile" HeaderText="Price Quartile"
SortExpression="PriceQuartile">
<ItemStyle HorizontalAlign="Center" />
</asp:BoundField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsWithPriceQuartile"
TypeName="ProductsBLLWithSprocs">
</asp:ObjectDataSource>
Rysunek 11 przedstawia tę stronę po odwiedzeniu za pośrednictwem przeglądarki. Należy pamiętać, że początkowo produkty są uporządkowane według ich ceny w kolejności malejącej, a każdy produkt ma przypisaną odpowiednią PriceQuartile
wartość. Oczywiście te dane można sortować według innych kryteriów z wartością kolumny kwartylu cen nadal odzwierciedlając klasyfikację produktu w odniesieniu do ceny (patrz Rysunek 12).
Rysunek 11. Produkty są uporządkowane według ich cen (kliknij, aby wyświetlić obraz pełnowymiarowy)
Rysunek 12. Produkty są uporządkowane według ich nazw (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Uwaga
Za pomocą kilku wierszy kodu możemy rozszerzyć obiekt GridView, tak aby wiersze produktów zostały kolorowe na podstawie ich PriceQuartile
wartości. Możemy kolorować te produkty w pierwszym kwartylu jasnozielony, te w drugim kwartylu jasnożółtym i tak dalej. Zachęcam do poświęć chwilę, aby dodać tę funkcjonalność. Jeśli potrzebujesz modułu odświeżania podczas formatowania kontrolki GridView, zapoznaj się z samouczkiem Custom Formatting Based Data (Formatowanie niestandardowe oparte na danych ).
Alternatywne podejście — tworzenie innego elementu TableAdapter
Jak pokazano w tym samouczku, podczas dodawania metody do kontrolki TableAdapter, która zwraca pola danych inne niż te zapisane przez zapytanie główne, możemy dodać odpowiednie kolumny do tabeli DataTable. Takie podejście sprawdza się jednak tylko wtedy, gdy w metodzie TableAdapter istnieje niewielka liczba metod, które zwracają różne pola danych i jeśli te alternatywne pola danych nie różnią się zbytnio od zapytania głównego.
Zamiast dodawać kolumny do tabeli DataTable, możesz zamiast tego dodać inny element TableAdapter do zestawu danych, który zawiera metody z pierwszego obiektu TableAdapter, który zwraca różne pola danych. W tym samouczku zamiast dodawać kolumnę PriceQuartile
do ProductsDataTable
obiektu (gdzie jest używana tylko przez GetProductsWithPriceQuartile
metodę), możemy dodać dodatkowy element TableAdapter do zestawu danych o nazwie ProductsWithPriceQuartileTableAdapter
, który użył Products_SelectWithPriceQuartile
procedury składowanej jako głównego zapytania. ASP.NET strony, które musiały uzyskać informacje o produkcie z kwartylem cen, będą używać ProductsWithPriceQuartileTableAdapter
wartości , a te, które nie mogły nadal korzystać z elementu ProductsTableAdapter
.
Dodając nowy element TableAdapter, tabele DataTable pozostają niezmienione, a ich kolumny dokładnie odzwierciedlają pola danych zwracane przez metody tableAdapter. Jednak dodatkowe elementy TableAdapters mogą wprowadzać powtarzające się zadania i funkcje. Jeśli na przykład te strony ASP.NET, które wyświetlały kolumnę PriceQuartile
, również potrzebne do zapewnienia obsługi wstawiania, aktualizowania i usuwania, ProductsWithPriceQuartileTableAdapter
muszą mieć odpowiednio InsertCommand
skonfigurowane właściwości , UpdateCommand
i DeleteCommand
. Chociaż te właściwości dublowałyby ProductsTableAdapter
s, ta konfiguracja wprowadza dodatkowy krok. Ponadto istnieją dwa sposoby aktualizowania, usuwania lub dodawania produktu do bazy danych — za pomocą ProductsTableAdapter
klas i ProductsWithPriceQuartileTableAdapter
.
Pobieranie dla tego samouczka zawiera klasę ProductsWithPriceQuartileTableAdapter
w zestawie NorthwindWithSprocs
danych, która ilustruje to alternatywne podejście.
Podsumowanie
W większości scenariuszy wszystkie metody w metodzie TableAdapter zwracają ten sam zestaw pól danych, ale istnieją sytuacje, w których określona metoda lub dwie mogą wymagać zwrócenia dodatkowego pola. Na przykład w samouczku Master/Detail Using a Bulleted List of Master Records with a Details DataList (Lista punktowana rekordów głównych z listą szczegółów dataList ) dodaliśmy metodę , CategoriesTableAdapter
która oprócz pól danych zapytania głównego zwróciła NumberOfProducts
pole, które zgłosiło liczbę produktów skojarzonych z każdą kategorią. W tym samouczku przyjrzeliśmy się dodawaniu metody w ProductsTableAdapter
pole, które zwróciło PriceQuartile
pole oprócz pól danych zapytania głównego. Aby przechwytywać dodatkowe pola danych zwracane przez metody tableAdapter, musimy dodać odpowiednie kolumny do tabeli DataTable.
Jeśli planujesz ręczne dodawanie kolumn do tabeli DataTable, zaleca się użycie procedur składowanych przez obiekt TableAdapter. Jeśli tableAdapter używa ad hoc instrukcji SQL, za każdym razem, gdy kreator konfiguracji tableAdapter zostanie uruchomiony wszystkie listy pól danych metod, zostaną przywrócone do pól danych zwracanych przez zapytanie główne. Ten problem nie obejmuje procedur składowanych, dlatego są one zalecane i były używane w tym samouczku.
Szczęśliwe programowanie!
Informacje o autorze
Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.
Specjalne podziękowania
Ta seria samouczków została przejrzyona przez wielu przydatnych recenzentów. Głównymi recenzentami tego samouczka byli Randy Schmidt, Jacky Goor, Bernadette Leigh i Hilton Giesenow. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresemmitchell@4GuysFromRolla.com .