Обеспечение взаимодействия Интернет-магазина с базой данных
11.2. Доработка страницы продуктов с использованием LINQ to SQL
После того, как разработано меню, позволяющее ограничивать категорию товара, которой интересуется пользователь, необходимо переработать страницу продуктов так, чтобы она извлекала сведения о продуктах из базы данных, и могла их ограничивать по категориям.
Для доступа к данным мы воспользуемся другой технологией, входящей в состав .NET Framework – LINQ to SQL. Эта технология позволяет извлекать данные из БД в виде связанных объектов, которые более привычны разработчику, программирующем на объекто-ориентированных языках программирования, и позволяет использовать язык интегрированных запросов LINQ для манипуляций с этими объектами.
Для того, чтобы добавить отображение таблиц данных в виде LINQ to SQL в проект, необходимо кликнуть правой клавишей мыши по папке App_Data, в контекстном меню выбрать пункт Add New Item. В открывшемся диалоговом окне ненужно выбрать элемент LINQ to SQL Classes (рис. 11.5).
После добавление классов в проект, откроется дизайнер классов (рис. 11.6). Добавим в него таблицы ProductCategory, ProductSubcategory, ProductModel, ProductModelIllustrtions, Product, ProductDescriptions, ProductModelProductDescriptionCulture, ProductPhoto, ProductProductPhoto и Productreview, перетащив их мышкой из окна Server Explorer.
Прежде чем приступить к дальнейшей работе, откроем файл DataClasses.designer.cs и увидим сгенерированный код для классов. Перейдем в класс Product и добавим в него следующий код:
public string FullSize { get { return Size + " " + SizeUnitMeasureCode; } }
Теперь мы определили собственное свойство у объекта product, которое отображает его размер с указанными единицами измерений. Стоит отметить, что это свойство вычислимое, оно не хранится в БД и его нельзя изменить.
Теперь перейдем к странице products/default.aspx и переопределим код левого PlaceHolder' а. прежде всего, добавим в него определение нового источника данных – LinqDataSource. Это можно сделать, набрав код руками, а можно перетащить соответствующий элемент из окна Toolbox и настроить его в специальном мастере. Так или иначе, должен получиться следующий код:
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="DataClassesDataContext" Select="new (ProductID, Name, ProductNumber, Color, ListPrice, Size, SizeUnitMeasureCode, WeightUnitMeasureCode, Weight, FullSize)" TableName="Product"> </asp:LinqDataSource>
В источнике данных LinqDataSource указано, что необходимо брать объекты типа Products, определенные в DataClassesDataContext, и предоставлять доступ компонентам, которые будут использовать этот источник данных только к тем свойствам, которые указаны в атрибуте Select. Теперь переопределим GridView так, чтобы он использовал новый источник данных:
<asp:GridView ID="GridViewProducts" runat="server" CellPadding="4" GridLines="None" CssClass="GridViewProduct" AllowSorting="True" AutoGenerateColumns="False" AllowPaging="True" DataSourceID="LinqDataSource1" OnSelectedIndexChanged="OnSelectedIndexChanged" > <RowStyle CssClass="tr_nechet" /> <AlternatingRowStyle CssClass="tr_chet" /> <Columns> <asp:CommandField SelectText="Выбор" ShowSelectButton="True" /> <asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True" SortExpression="ProductID" Visible="False" /> <asp:BoundField DataField="ProductNumber" HeaderText="Номер продукта" ReadOnly="True" SortExpression="ProductNumber" /> <asp:BoundField DataField="Name" HeaderText="Название" ReadOnly="True" SortExpression="Name" /> <asp:BoundField DataField="Color" HeaderText="Цвет" ReadOnly="True" SortExpression="Color" /> <asp:BoundField DataField="ListPrice" HeaderText="Цена" ReadOnly="True" SortExpression="ListPrice" NullDisplayText="Цена не указана" DataFormatString="{0:F2}" /> <asp:BoundField DataField="FullSize" HeaderText="Размер" ReadOnly="True" SortExpression="FullSize" /> <asp:TemplateField HeaderText="Вес" SortExpression="Weight" > <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("Weight") + " " + Eval("WeightUnitMeasureCode") %>'> </asp:Label> </ItemTemplate> </asp:TemplateField> </Columns> <PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" /> <SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" /> <HeaderStyle CssClass="tr_main" /> </asp:GridView>
Здесь стоит обратить внимание на то, что для GridView установлен источник данных ( DataSourceID="LinqDataSource1" ), разрешены операции сортировки и постраничного вывода ( AllowSorting="True" и AllowPaging="True" ). При этом изменилось и определение колонок – теперь мы можем использовать BoundField, в которых при помощи атрибута DataField указать, какое свойство необходимо отображать. Также, для свойства ListPrice, определяющего цену на товар задан формат вывода ( DataFormatString="{0:F2}" ), который определяет, что строку надо выводить как число с двумя знаками после запятой. Также, для примера, GridView содержит один столбец, использующий TemplateField, который отображает вес товара вместе с единицей измерения веса. Это альтернативный способ добиться отображения сложных полей (для этих же целей мы определили свойство FullSize ).
Теперь необходимо изменить метод Page_Load. В нем нам необходимо ввести ограничения на извлекаемые данные, ограничив категорию и подкатегорию продуктов. Для этого у объектов LinqDataSource есть свойства Where и WhereParameters. При нажатии на определенный пункт меню, происходит переадресация на страницу products/default.aspx, при этом категория и подкатегория передаются через параметры category и subCategory. Прежде всего, необходимо сбросить текущие фильтры, после чего, если определена подкатегория (это можно узнать, проверив содержимое Request.QueryString["subCategory"] ) то достаточно указать свойство Where = "ProductSubcategoryID == @subCategory", а в коллекцию WhereParameters добавить новый параметр "subCategory" со значением, переданным в строке запроса – Request.QueryString["subCategory"]. Если же подкатегория не была указана, но была указана категория, то свойству where необходимо присвоить значение "ProductSubcategory.ProductCategoryID == @category" и задать параметр category в WhereParameters.
Ниже приведен полный код метода Page_Load.
protected void Page_Load(object sender, EventArgs e) { GridViewProducts.DataKeyNames = new string[] { "ProductID" }; LinqDataSource1.Where = ""; LinqDataSource1.WhereParameters.Clear(); if (!string.IsNullOrEmpty(Request.QueryString["subCategory"])) { LinqDataSource1.Where = "ProductSubcategoryID == @subCategory"; LinqDataSource1.WhereParameters.Add("subCategory", DbType.Int32, Request.QueryString["subCategory"]); } else { if (!string.IsNullOrEmpty(Request.QueryString["category"])) { LinqDataSource1.Where = "ProductSubcategory.ProductCategoryID == @category"; LinqDataSource1.WhereParameters.Add("category", DbType.Int32, Request.QueryString["category"]); } } }
На рис. 11.7 представлен вид страницы продуктов при выбранном пункте меню "Mountain Bikes".