(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

ASP.Net. Лекция 7. Работа с базами данных. Продолжение. Элементы-источники данных (Data Source Controls) (исходники)

Лекция 6

Объектная модель источников данных

Для работы с данными в ASP.NET существуют две группы специальные элементы управления. Первая предназначена для того, чтобы осуществлять связь с источниками данных. Вторая группа служит для отображения данных.

В Visual Studio .NET 2002 и 2003 можно было создавать привязки данных к странице по технологии "drag-and-drop". Эта технология была удобна тем, что упрощала написание кода, но она усложняла его модификацию. Объекты данных DataAdapter и DataConnection напрямую связывались Visual Studio 2005 формой. Сейчас это тоже возможно, но технология изменилась. Введена новая объектная модель источников данных. Классы-источники данных обеспечивают лучшую абстрактизацию, чем использование классов ADO.

Один из компонентов это модели - это строка соединения с источником данных. В Vsual Studio 2005 все строки добавляются в конфигурационных файл web.config.

  <configuration> 
    <appSettings/> 
    <connectionStrings> 
    <add name="DemoBaseConnectionString1" connectionString="Data Source= \SQLEXPRESS;Initial Catalog=DemoBase;
  Integrated Security=True" 
     providerName="System.Data.SqlClient" /> 
    <add name="DatabaseConnectionString1" connectionString="Data Source=.\SQLEXPRESS;
AttachDbFilename="C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\QuickStart\aspnet\samples\data\App_Data\Database.mdf";
Integrated Security=True;Connect Timeout=30;User Instance=True" 
     providerName="System.Data.SqlClient" /> 
    </connectionStrings> 
  

Разные страницы могут использовать одну и ту же строку соединения. Если по какой-либо причине соединение нужно будет изменить, например, сервер изменил свое местоположение, изменения придется вводить централизованно только в файле web.config.

Окно Data WebMatrix позволяет соединяться только с базами Access и SQL Server. Также работает перетаскивание, но требуется, чтобы в таблице имелся первичный ключ. Он не поддерживает и представлений (View) Access.

В WebMatrix существуют собственные элементы управления с префиксом wmx - AccessDataSourceControl и SqlDataSourceControl. Строка соединения записывается в свойство ConnectionString такого элемента управления. Программа WebMatrix служила испытательным полигоном для тех новых возможностей, которые позже были добавлены в Visual Studio .NET 2005.

  <wmx:AccessDataSourceControl id="AccessDataSourceControl1" runat="server" 
ConnectionString="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; 
Data Source=D:\My_DOCs\guestbook.mdb" SelectCommand="SELECT * FROM [guestbook]">
  </wmx:AccessDataSourceControl>
  <wmx:SqlDataSourceControl id="SqlDataSourceControl1" runat="server" ConnectionString="server='SQLEXPRESS'; 
trusted_connection=true; database='Northwind'" SelectCommand="SELECT * FROM [Categories]" DeleteCommand="" 
UpdateCommand=""></wmx:SqlDataSourceControl>
  

Итак, строка соединения состоит из указания провайдера, если это Oledb, сервера и базы на этом сервере. База может находиться в отдельном файле с расширением.mdf. При соединении через ODBC указывается имя источника данных, тип базы, путь к файлу и драйвер.

  <add name="ConnectionString1" connectionString="DSN=BB;DBQ=D:\Programming\Brainbench\brainbench.mdb;
DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;" providerName="System.Data.Odbc" />
  

Строки могут показаться сложными, но они создаются, когда мы просто перетаскиваем на форму в Design mode таблицу или запрос. При наличии опыта можно писать их и самим.

Строками соединений можно манипулировать и программно.

    protected void Page_Load(object sender, EventArgs e) 
    { 
      if (!Page.IsPostBack) 
      { 
        // Создание класса ConnectionStringSettings 
        ConnectionStringSettings conn = new ConnectionStringSettings(); 
        conn.ConnectionString = "Server=localhost; " + 
        "User ID=sa;Password=m1d2ffnkl; " + 
        "Database=Northwind;Persist Security Info=True"; 
        conn.Name = "Northwind ConnectionString"; 
        conn.ProviderName = "System.Data.SqlClient"; 
        //Добавление строки в файл web.config 
        ConfigurationManager.ConnectionStrings.Add(conn); 
      } 
    } 
  

Элементы-источники данных (Data Source Controls)

Эти элементы облегчают работу с ADO.NET, инкапсулируя работу с соединениями, командами и адаптерами. Они реализуют интерфейс IDataSource, в котором определен базовый набор возможностей работы с источниками данных. Большинство этих классов предоставляют функциональность для чтения и записи. Они являются обертками объектов ADO.NET. В предыдущих версиях надо было создавать объекты ADO самим, и связывать элементы-управления с ними посредством команды DataBind. Например:

  <asp:BulletedList ID="BulletedList1" runat="server" BulletStyle="Square" 
DataTextField="CategoryName" DataValueField="CategoryID"> 
  </asp:BulletedList> 
  protected void Page_Load(object sender, EventArgs e) 
  { 
      SqlConnection conn = new SqlConnection(@"Data Source=(local)\sqlexpress;
  Initial Catalog=Northwind;Integrated Security=True"); 
      SqlCommand cmd = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories", conn); 
      SqlDataAdapter da = new SqlDataAdapter(cmd); 
      DataSet ds = new DataSet(); 
      da.Fill(ds); 
      BulletedList1.DataSource = ds; 
      BulletedList1.DataBind(); 
  } 
  

Теперь элементы управления связываются c элементом-источником посредством свойства DataSourceID. Любой класс - источник данных может быть связан почти с любым классом для отображения данных. Это предоставляет большую гибкость.

Всего в ASP .NET 5 элементов-источников данных: SqlDataSource, AccessDataSource и ObjectDataSource для работы с табличными источниками данных и XmlDataSource и SiteMapDataSource - для работы с иерархическими данными.

SqlDataSource позволяет соединяться с большинством реляционных СУБД. Sql в названии класса означает, что служит для соединения с базами, которые понимают язык запросов Sql, а не только с MS SQL Server.

AccessDataSource оптимизирован для работы с базами Access. Например,

  <asp:AccessDataSource ID="AccessDataSource1" runat="server" DataFile="~/App_Data/guestbook.mdb" 
      SelectCommand="SELECT [WriteDate], [UserName], [UserMail], [Message] FROM [guestbook]"> 
  </asp:AccessDataSource> 
  

SiteMapDataSource - это специализация XmlDataSource, работает с файлами навигации по сайту и служит источником данных для элементов управления навигации.

ObjectDataSource нужен для соединения с написанными программистом бизнес-объектами.

Элементы - источники данных предназначены для двустороннего обмена данными, то есть как для чтения, так и для записи. Сами по себе они ничего не отображают. Данные будут доступны подключенным к ним элементам управления.

SqlDataSource

SqlDataSource объединяет в себе возможности SqlConnection и SqlDataAdapter(плюс дополнительные).

Итак, у нас есть строка подключения в файле web.config.

  <add name="DemoBaseConnectionString1" connectionString="Data Source=(local)\SQLEXPRESS;Initial Catalog=DemoBase;Integrated Security=True" 
  providerName="System.Data.SqlClient" /> 
  

В свойство ConnectionString записывается эта строка.

  <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:DemoBaseConnectionString1 %>" 
      ProviderName="<%$ ConnectionStrings:DemoBaseConnectionString1.ProviderName %>" 
  </asp:SqlDataSource> 
  

В свойстве DataSourceMode SqlDataSource задается, посредством DataReader или DataSet получаются данные. При чтении посредством DataReader некоторые возможности не поддерживаются.

Получение данных связано со свойствами, похожими на свойства SqlDataAdapter: SelectCommand, SelectCommandType, DeleteCommand, DeleteCommandType и так далее. SelectCommandType может быть 2 типов - Text и StoredProcedure. Команды выполняются, когда вызываются соответствующие методы.

Метод Select вызывается с параметром типа DataSourceSelectArguments и возвращает DataSet или IDataReader в зависимости от значения свойства DataSourceMode, остальные же методы вызываются без параметров и возвращают количество обработанных строк.

  <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" 
      SelectCommand="SELECT * FROM [Customers]" 
   ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>"> 
  </asp:SqlDataSource>
  

Этот SqlDataSource читает все записи из таблицы Customers с помощью простого запроса в DataSet.

  <asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ 
ConnectionStrings:NorthwindConnectionString %>" 
      SelectCommand="[Ten Most Expensive Products]" DeleteCommandType="StoredProcedure"> 
  </asp:SqlDataSource>
  

Метод Select нет необходимости вызывать явно. Он вызывается автоматически, когда связанному с SqlDataSource элементу нужны данные для отображения.

Процедуры сервера обычно имеют параметры. Поэтому предусмотрены также коллекции параметров. Сами параметры могут быть обычными или связанными с элементами управления.

Значения параметров можно получать и из других разнообразных источников.

Есть несколько классов параметров - наследников класса Parameter: CookieParameter использует значение ключа файла cookie, FormParameter - переменных формы, QuerystringParameter адресной строки, ProfileParameter профиля пользователя и SessionParameter -переменной сессии.

  <asp:Parameter Name="UID" Type="Int32" DefaultValue="0" />
  

Такой тип параметров используется, если SqlDataSource используется как источник данных для элементов с автоматическим связыванием - GridView, FormView, DetailsView. Значение параметра передается во «внутренностях» этих элементов.

В других случаях используется ControlParameter, то есть значение параметра берется из элемента управления. Также задается свойство, откуда и берется значение. Хотя если это Text, его можно не писать.

  <asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ 
ConnectionStrings:NorthwindConnectionString %>" 
      SelectCommand="Sales by Year" SelectCommandType="StoredProcedure"> 
      <SelectParameters> 
      <asp:Parameter Name="Beginning_Date" Type="DateTime" DefaultValue="01.01.1998"/> 
      <asp:ControlParameter Name="Ending_Date" Type="DateTime" ControlID="Calendar2"/> 
      </SelectParameters> 
  </asp:SqlDataSource> 
  

Источник параметра типа дата - элемент управления календарь. При заданном свойстве параметра ConvertEmptyToNull текстовый параметр конвертируется в Null, если он пустой(равен System.String.Empty).

Свойство CancelSelectOnNullParameter определяет, будет ли прерван запрос, если значение какого-либо параметра равно Null.

  <asp:SqlDataSource ID="SqlDataSource4" runat="server" ConnectionString="<%$ 
ConnectionStrings:NorthwindConnectionString %>" 
      SelectCommand="SELECT * FROM [Customers] where @Country is null or Country = @Country" 
   ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>" CancelSelectOnNullParameter="False"> 
      <SelectParameters>  
          <asp:QueryStringParameter Name="Country" QueryStringField="Country" />  
      </SelectParameters> 
  </asp:SqlDataSource> 
  

Этот запрос будет брать параметр из командной строки, например

  http://localhost:3457/WebSite4/CustomersByCountry.aspx?Country=UK
  

Кеширование

Кеширование нужно для увеличения эффективности работы с данными. При включенном кешировании SqlDataSource «запоминает» большое количество записей на заданное время, даже если все данные не отображаются сразу, но могут понадобиться при перелистывании. Например, студент читает первую страницу лекции, логично, что он вскоре перейдет ко второй. Если сервер хранит в оперативной памяти все страницы лекции, он их оперативно выдаст, не обращаясь к базе.

При включенном кешировании данные читаются «большим куском», а выборка записей происходит с помощью фильтрования.

В SqlDataSource кеширование и сортировка возможны только при получении данных через DataSet. Если DataSourceMode равно DataReader, а EnableCaching - True, будет выброшено исключение NonSupportedException.

Длительность кеширования можно задать в свойстве CacheDuration, это может быть определенное количество секунд или Infinite, то есть данные никогда не обновляются.

Поведение кеширования зависит от сочетания свойств CacheDuration и CacheExpirationPolicy. Если значение CacheExpirationPolicy равно Absolute, то элемент запрашивает информацию через промежутки времени, определенные в CacheDuration, а старую стирает из памяти. Если CacheExpirationPolicy равен значению Sliding, то SqlDataSource начинает отсчет времени после каждого к нему запроса. Данные из кеша устаревают, если в течение времени CacheDuration не было ни одного Select-запроса.

В FilterExpression задается выражение для фильтрации, причем формат этих выражений аналогичен тому, что используется для форматирования строк с параметрами в фигурных скобках {0}, {1}, в которые подставляются значения из источника, указанного в FilterParameters.

  <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ 
ConnectionStrings:NorthwindConnectionString %>" 
      SelectCommand="SELECT * FROM [Customers]" ProviderName="<%$ 
  ConnectionStrings:NorthwindConnectionString.ProviderName %>" 
      EnableCaching="True" CacheExpirationPolicy="Sliding"> 
  </asp:SqlDataSource> 
  

У этого элемента включено кеширование, и он является источником данных для GridView.

  <asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ 
ConnectionStrings:NorthwindConnectionString %>" 
      SelectCommand="SELECT * FROM [Customers]" ProviderName="<%$ 
  ConnectionStrings:NorthwindConnectionString.ProviderName %>" 
  FilterExpression="CustomerID=’{0}’ " 
  <FilterParameters> 
  <asp:ControlParameter Name="CustomerID" ControlId="GridView1" 
  PropertyName="SelectedValue"></asp:ControlParameter> 
  </FilterParameters> 
      </asp:SqlDataSource> 
  

А у этого включена фильтрация, и он является источником данных для DetailsView. Контрол DetailsView всегда отображает одну запись, при этом в данном случае эта та запись, которая выбрана в контроле GridView1.

Сортировка

В свойстве SortParameterName можно записать список полей, по которым проводится сортировка, возможно с добавлением опции Desc для сортировки в порядке убывания. Параметры передаются в команду Select, если это серверная процедура.

ObjectDataSource

Как уже было сказано, этот класс работает с бизнес-объектами. А что же это такое? Это такие классы, которые инкапсулируют логику работы с данными, нужными в приложении. Класс бизнес-объекта может быть написан на любом языке .NET. Как и все классы, он располагается в папке App_Code. ObjectDataSource работает как связующее звено между бизнес-объектами и элементами управления, отображающими данные. Получается многоуровневая компонентная архитектура. Классы бизнес-объектов могут поменять свое внутреннее представление, и это никак не отразится на страницах, которые их используют. ObjectDataSource работает во многом так же, как SqlDataSource, с той разницей, что он имеет дело не с базой данных, а с классом.

Свойство TypeName класса ObjectDataSource указывает на используемый класс. Класс бизнес-объекта должен поддерживать конструктор и 4 метода(может и больше) - для чтения, редактирования, удаления и добавления данных в источник данных. Элемент управления ObjectDataSource пользуется этими методами.

Например, свойство SelectMethod указывает на метод класса бизнес-объекта, который возвращает данные.

Откуда бизнес-объект берет данные, ему не важно. Некоторые бизнес-объекты работают с базами данных, некоторые с сессией или текстовыми файлами. Главное, что метод, который он использует для чтения, должен возвращать класс, реализующий интерфейс IEnumerable. UpdateMethod- метод, который обновляет данные. Аналогичную функцию выполняют DeleteMethod и InsertMethod.

Класс бизнеса-объект может поддерживать метод SelectCount, который возвращает общее количество объектов в источнике данных.ObjectDataSource вызывает этот метод, чтобы реализовать разбиение на страницы.

Рассмотрим это на примере:

  public class Continent 
  { 
      ArrayList ContinentArrayList; 
      public Continent() 
      { 
          ContinentArrayList = new ArrayList(); 
          ContinentArrayList.Add("Worldwide"); 
          ContinentArrayList.Add("America"); 
          ContinentArrayList.Add("Africa"); 
          ContinentArrayList. Add("Asia-Pacific"); 
      } 
      public ArrayList List() 
      { 
          return ContinentArrayList; 
      } 
      public int SelectCount() 
      { 
          return ContinentArrayList.Length; 
      } 
  } 
  

Даже такой примитивный класс может использоваться как источник данных для ObjectDataSource, так как ArrayList реализует IEnumerable. Вместо свойств *Command ObjectDataSource использует *Method.

  <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
       SelectMethod="List" TypeName=" Continent "> 
  </asp:ObjectDataSource> 
  <asp:RadioButtonList ID="RadioButtonList1" runat="server"  
      DataSourceID="ObjectDataSource1"> 
  </asp:RadioButtonList></div> 
  

Достигается тот же эффект, что и раньше, когда данные вставлялись на странице или в классе страницы, но теперь получение данных инкапсулировано в классе Continent. Класс может изменить способ получения данных, не меняя интерфейса. Чаще всего данные все-таки получают из баз данных, XML-файлов или веб-сервисов. Классы бизнес-логики могут разрабатывать одни члены команды, а заниматься дизайном страниц другие. Их можно использовать и в обычных приложениях в Windows Forms.

ObjectDataSource может работать и с типизированными наборами данных, которые можно создать с помощью мастера. Попробуем это сделать на примере таблицы Customers. Создайте в папке App_Code новый файл и в диалоге выбора типа файла выберите dataset. Назовите его Customers. Мастер предложит выбрать строку соединения. Выберите NorthWindConnectionString (если его нет в проекте, создайте, как показано в предыдущей лекции). На следующем шаге мастер предложит выбрать из трех вариантов: использование запросов SQL, создание хранимых процедур или использование готовых процедур. Выберите второе, так как готовых процедур, которые бы обновляли данные, в базе Northwind нет. На следующем шаге нужно будет создать процедуры, это можно сделать с помощью QueryBuilder, очень похожем на дизайнер запросов в MS Access. В списке таблиц выберите Customers, а в таблице несколько полей. Должен получиться запрос

SELECT CustomerID, CompanyName, ContactName, ContactTitle, Country, City FROM Customers

После этого закройте QueryBuilder и нажмите на кнопку AdvancedOptions.

Как видите, мастер предлагает сгенерировать остальные команды самому. Прекрасно, мы не против. На следующем шаге мастер предложит изменить имена процедур и увидеть, что же он сгенерировал. Через остальные шаги можно пройти без изменений.

В результате получится файл Customers.xsd, по формату - файл схемы XML(XML Schema Definition, в котором описано и создание процедур, и команды для работы с базой вместе с параметрами, и еще один маленький файл Customers.xss. После этого проект желательно скомпилировать.

Мы получили компонент данных. Все готово для связывания его с ObjectDataSource. Перетащите значок нужного класса на форму и с помощью SmartTag запустите еще один мастер. На первом шаге настройте его на CustomersDataAdapters.CustomersDataAdapter. На втором надо выбрать подходящие функции для команд Select, Update, Delete, Insert. Вариантов будет немного и Finish. Можно привязывать наш ObjectDataSource к любому подходящему элементу управления, например GridView.

  <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetData" 
TypeName="CustomersTableAdapters.CustomersTableAdapter" DeleteMethod="Delete" InsertMethod="Insert" 
OldValuesParameterFormatString="original_{0}" UpdateMethod="Update"> 
      <DeleteParameters> 
          <asp:Parameter Name="Original_CustomerID" Type="String" /> 
      </DeleteParameters> 
      <UpdateParameters> 
          <asp:Parameter Name="CustomerID" Type="String" /> 
          <asp:Parameter Name="CompanyName" Type="String" /> 
          <asp:Parameter Name="ContactName" Type="String" /> 
          <asp:Parameter Name="ContactTitle" Type="String" /> 
          <asp:Parameter Name="Country" Type="String" /> 
          <asp:Parameter Name="City" Type="String" /> 
          <asp:Parameter Name="Original_CustomerID" Type="String" /> 
      </UpdateParameters> 
      <InsertParameters> 
          <asp:Parameter Name="CustomerID" Type="String" /> 
          <asp:Parameter Name="CompanyName" Type="String" /> 
          <asp:Parameter Name="ContactName" Type="String" /> 
          <asp:Parameter Name="ContactTitle" Type="String" /> 
          <asp:Parameter Name="Country" Type="String" /> 
          <asp:Parameter Name="City" Type="String" /> 
      </InsertParameters> 
  </asp:ObjectDataSource> 
      <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" 
      AutoGenerateColumns="False" DataKeyNames="CustomerID" DataSourceID="ObjectDataSource1"> 
      <Columns> 
          <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowSelectButton="True" /> 
          <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" ReadOnly="True" SortExpression="CustomerID" /> 
          <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" SortExpression="CompanyName" /> 
          <asp:BoundField DataField="ContactName" HeaderText="ContactName" SortExpression="ContactName" /> 
          <asp:BoundField DataField="ContactTitle" HeaderText="ContactTitle" SortExpression="ContactTitle" /> 
          <asp:BoundField DataField="Country" HeaderText="Country" SortExpression="Country" /> 
          <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" /> 
      </Columns> 
  </asp:GridView>
  

Класс бизнес-объекта создается неявно. Из файла .xsd vожно получить класс типизированного набора данных на языке C# с помощью утилиты xsd.exe.

  xsd.exe /dataset /language:CS Customers.xsd.
  

Из одного класса могут получать данные разные элементы ObjectDataSource. В приложении Personal Starter Kit определен класс PhotoManager, который работает с базой данных Personal.mdf.

    public static Stream GetPhoto(int photoid, PhotoSize size) 
    { 
      using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Personal"].ConnectionString)) { 
        using (SqlCommand command = new SqlCommand("GetPhoto", connection)) { 
          command.CommandType = CommandType.StoredProcedure; 
          command.Parameters.Add(new SqlParameter("@PhotoID", photoid)); 
          command.Parameters.Add(new SqlParameter("@Size", (int)size)); 
          bool filter = !(HttpContext.Current.User.IsInRole("Friends") // HttpContext.Current.User.IsInRole("Administrators")); 
          command.Parameters.Add(new SqlParameter("@IsPublic", filter)); 
          connection.Open(); 
          object result = command.ExecuteScalar(); 
          try { 
            return new MemoryStream((byte[])result); 
          } catch { 
            return null; 
          } 
        } 
      } 
  

В этой функции полезно для усвоения получение двоичной информации, например, изображений, из базы данных.

Заключение

Мы рассмотрели классы-элементы управления, которые отвечают за получение данных. Эти классы предназначены в первую очередь для облегчения труда программиста по сравнению с предыдущими версиями. Наиболее простые страницы с помощью этих элементов создаются даже без написания программного кода. В следующих двух лекциях подробнее займемся отображением данных. XMLDataSource будет рассмотрен в лекции 10, а SiteMapSource - в 11.



 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 20.04.2007 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft 365 Apps for business (corporate)
Microsoft 365 Business Standard (corporate)
Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год.
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год.
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
Программирование на Visual Basic/Visual Studio и ASP/ASP.NET
Работа в Windows и новости компании Microsoft
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100