Sdílet prostřednictvím


Část 7: Přidání funkcí

Joe Stagner

Tailspin Spyworks ukazuje, jak je mimořádně jednoduché vytvářet výkonné a škálovatelné aplikace pro platformu .NET. Ukazuje, jak používat skvělé nové funkce v ASP.NET 4 k vytvoření online obchodu, včetně nakupování, pokladny a správy.

Tato série kurzů podrobně popisuje všechny kroky k sestavení ukázkové aplikace Tailspin Spyworks. Část 7 přidává další funkce, jako je kontrola účtu, recenze produktů a "oblíbené položky" a "také zakoupené" uživatelské ovládací prvky.

Přidání funkcí

I když uživatelé můžou procházet náš katalog, umísťovat položky do nákupního košíku a dokončit proces placení, máme k dispozici řadu podpůrných funkcí, které zahrneme ke zlepšení našeho webu.

  1. Kontrola účtu (výpis zadaných objednávek a zobrazení podrobností))
  2. Přidejte na úvodní stránku nějaký kontextový obsah.
  3. Přidejte funkci, která uživatelům umožní zkontrolovat produkty v katalogu.
  4. Vytvořte uživatelský ovládací prvek, který zobrazí oblíbené položky a umístí tento ovládací prvek na přední stránku.
  5. Vytvořte uživatelský ovládací prvek "Také zakoupeno" a přidejte ho na stránku s podrobnostmi o produktu.
  6. Přidejte stránku kontaktu.
  7. Přidejte stránku O aplikaci.
  8. Globální chyba

Kontrola účtu

Ve složce "Účet" vytvořte dvě stránky .aspx, jednu s názvem OrderList.aspx a druhou s názvem OrderDetails.aspx.

OrderList.aspx bude využívat ovládací prvky GridView a EntityDataSource stejně jako dříve.

<div class="ContentHead">Order History</div><br />

<asp:GridView ID="GridView_OrderList" runat="server" AllowPaging="True" 
              ForeColor="#333333" GridLines="None" CellPadding="4" Width="100%" 
              AutoGenerateColumns="False" DataKeyNames="OrderID" 
              DataSourceID="EDS_Orders" AllowSorting="True" ViewStateMode="Disabled" >
  <AlternatingRowStyle BackColor="White" />
  <Columns>
    <asp:BoundField DataField="OrderID" HeaderText="OrderID" ReadOnly="True" 
                    SortExpression="OrderID" />
    <asp:BoundField DataField="CustomerName" HeaderText="Customer" 
                    SortExpression="CustomerName" />
    <asp:BoundField DataField="OrderDate" HeaderText="Order Date" 
                    SortExpression="OrderDate" />
    <asp:BoundField DataField="ShipDate" HeaderText="Ship Date" 
                    SortExpression="ShipDate" />
    <asp:HyperLinkField HeaderText="Show Details" Text="Show Details" 
                 DataNavigateUrlFields="OrderID" 
                 DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}" />
  </Columns>
  <FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
  <HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
  <PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
  <RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
  <SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" />
  <SortedAscendingCellStyle BackColor="#FDF5AC" />
  <SortedAscendingHeaderStyle BackColor="#4D0000" />
  <SortedDescendingCellStyle BackColor="#FCF6C0" />
  <SortedDescendingHeaderStyle BackColor="#820000" />
  <SortedAscendingCellStyle BackColor="#FDF5AC"></SortedAscendingCellStyle>
  <SortedAscendingHeaderStyle BackColor="#4D0000"></SortedAscendingHeaderStyle>
  <SortedDescendingCellStyle BackColor="#FCF6C0"></SortedDescendingCellStyle>
  <SortedDescendingHeaderStyle BackColor="#820000"></SortedDescendingHeaderStyle>
</asp:GridView>

<asp:EntityDataSource ID="EDS_Orders" runat="server" EnableFlattening="False" 
                      AutoGenerateWhereClause="True" 
                      Where="" 
                      OrderBy="it.OrderDate DESC"
                      ConnectionString="name=CommerceEntities"  
                      DefaultContainerName="CommerceEntities" 
                      EntitySetName="Orders" >
   <WhereParameters>
      <asp:SessionParameter Name="CustomerName" SessionField="UserName" />
   </WhereParameters>
</asp:EntityDataSource>

EntityDataSource vybere záznamy z tabulky Orders filtrované na UserName (viz WhereParameter), které jsme nastavili v proměnné relace, když se uživatel přihlásí.

Všimněte si také těchto parametrů v Poli hypertextových odkazů objektu GridView:

DataNavigateUrlFields="OrderID" DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}"

Ty určují odkaz na zobrazení Podrobnosti objednávky pro každý produkt a určují pole OrderID jako parametr QueryString stránky OrderDetails.aspx.

OrderDetails.aspx

Použijeme ovládací prvek EntityDataSource pro přístup k Objednávce a FormView k zobrazení dat Objednávky a další EntityDataSource s GridView k zobrazení všech řádkových položek objednávky.

<asp:FormView ID="FormView1" runat="server" CellPadding="4" 
                             DataKeyNames="OrderID" 
                             DataSourceID="EDS_Order" ForeColor="#333333" Width="250px">
   <FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
   <HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
   <ItemTemplate>
      OrderID : <%# Eval("OrderID") %><br />
      CustomerName : <%# Eval("CustomerName") %><br />
      Order Date : <%# Eval("OrderDate") %><br />
      Ship Date : <%# Eval("ShipDate") %><br />
   </ItemTemplate>
   <PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
   <RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
</asp:FormView>
<asp:EntityDataSource ID="EDS_Order" runat="server"  EnableFlattening="False" 
                      ConnectionString="name=CommerceEntities" 
                      DefaultContainerName="CommerceEntities" 
                      EntitySetName="Orders" 
                      AutoGenerateWhereClause="True" 
                      Where="" 
                      EntityTypeFilter="" Select="">
   <WhereParameters>
      <asp:QueryStringParameter Name="OrderID" QueryStringField="OrderID" Type="Int32" />
   </WhereParameters>
</asp:EntityDataSource>

<asp:GridView ID="GridView_OrderDetails" runat="server" 
              AutoGenerateColumns="False" 
              DataKeyNames="ProductID,UnitCost,Quantity" 
              DataSourceID="EDS_OrderDetails" 
              CellPadding="4" GridLines="Vertical" CssClass="CartListItem" 
              onrowdatabound="MyList_RowDataBound" ShowFooter="True" 
              ViewStateMode="Disabled">
   <AlternatingRowStyle CssClass="CartListItemAlt" />
   <Columns>
     <asp:BoundField DataField="ProductID" HeaderText="Product ID" ReadOnly="True" 
                     SortExpression="ProductID"  />
     <asp:BoundField DataField="ModelNumber" HeaderText="Model Number"  
                     SortExpression="ModelNumber" />
     <asp:BoundField DataField="ModelName" HeaderText="Model Name" 
                     SortExpression="ModelName" />
     <asp:BoundField DataField="UnitCost" HeaderText="Unit Cost" ReadOnly="True" 
                     SortExpression="UnitCost" DataFormatString="{0:c}" />
     <asp:BoundField DataField="Quantity" HeaderText="Quantity" ReadOnly="True" 
                     SortExpression="Quantity" />
     <asp:TemplateField> 
       <HeaderTemplate>Item Total</HeaderTemplate>
       <ItemTemplate>
         <%# (Convert.ToDouble(Eval("Quantity")) *  Convert.ToDouble(Eval("UnitCost")))%>
       </ItemTemplate>
     </asp:TemplateField>
   </Columns>
   <FooterStyle CssClass="CartListFooter"/>
   <HeaderStyle  CssClass="CartListHead" />
 </asp:GridView> 
 <asp:EntityDataSource ID="EDS_OrderDetails" runat="server" 
                       ConnectionString="name=CommerceEntities" 
                       DefaultContainerName="CommerceEntities" 
                       EnableFlattening="False" 
                       EntitySetName="VewOrderDetails" 
                       AutoGenerateWhereClause="True" 
                       Where="">
   <WhereParameters>
     <asp:QueryStringParameter Name="OrderID" QueryStringField="OrderID" Type="Int32" />
   </WhereParameters>
</asp:EntityDataSource>

V souboru Code Behind (OrderDetails.aspx.cs) máme dvě malé části úklidu.

Nejprve se musíme ujistit, že OrderDetails vždy dostane OrderId.

protected void Page_Load(object sender, EventArgs e)
{
  if (String.IsNullOrEmpty(Request.QueryString["OrderId"]))
     {
     Response.Redirect("~/Account/OrderList.aspx");
     }
}

Musíme také vypočítat a zobrazit celkový počet objednávek z řádkových položek.

decimal _CartTotal = 0;

protected void MyList_RowDataBound(object sender, GridViewRowEventArgs e)
{
  if (e.Row.RowType == DataControlRowType.DataRow)
     {
     TailspinSpyworks.Data_Access.VewOrderDetail myCart = new 
                                                        Data_Access.VewOrderDetail();
     myCart = (TailspinSpyworks.Data_Access.VewOrderDetail)e.Row.DataItem;
     _CartTotal += Convert.ToDecimal(myCart.UnitCost * myCart.Quantity);
     }
   else if (e.Row.RowType == DataControlRowType.Footer)
     {
     e.Row.Cells[5].Text = "Total: " + _CartTotal.ToString("C");
   }
}

Domovská stránka

Pojďme na stránku Default.aspx přidat statický obsah.

Nejprve vytvořím složku "Obsah" a v ní složku Images (a přiložím obrázek, který se má použít na domovské stránce).

Do dolního zástupného symbolu stránky Default.aspx přidejte následující kód.

<h2>
  <asp:LoginView ID="LoginView_VisitorGreeting" runat="server">
    <AnonymousTemplate>
       Welcome to the Store !
    </AnonymousTemplate>
    <LoggedInTemplate>
      Hi <asp:LoginName ID="LoginName_Welcome" runat="server" />. Thanks for coming back. 
    </LoggedInTemplate>
  </asp:LoginView>
</h2>

<p><strong>TailSpin Spyworks</strong> demonstrates how extraordinarily simple it is to create powerful, scalable applications for the .NET platform. </p>
<table>
  <tr>
    <td>               
      <h3>Some Implementation Features.</h3>
      <ul>
                <li><a href="#">CSS Based Design.</a></li>
                <li><a href="#">Data Access via Linq to Entities.</a></li>
                <li><a href="#">MasterPage driven design.</a></li>
                <li><a href="#">Modern ASP.NET Controls User.</a></li>
                <li><a href="#">Integrated Ajac Control Toolkit Editor.</a></li>
        </ul>
    </td>
    <td>
        <img src="Content/Images/SampleProductImage.gif" alt=""/>
    </td>
  </tr>
</table>
    
<table>
  <tr>
    <td colspan="2"><hr /></td>
  </tr>
  <tr>
    <td>               
        <!-- Popular Items -->
    </td>
    <td>  
      <center><h3>Ecommerce the .NET 4 Way</h3></center>
      <blockquote>
        <p>
        ASP.NET offers web developers the benefit of more that a decade of innovation. 
        This   demo leverages many of the latest features of ASP.NET development to     
        illustrate really simply building rich web applications with ASP.NET can be. 
        For more information about build web applications with ASP.NET please visit the 
        community web site at www.asp.net
        </p>
      </blockquote>
    </td>
  </tr>
</table>

<h3>Spyworks Event Calendar</h3>
<table>
  <tr class="rowH">
    <th>Date</th>
    <th>Title</th>
    <th>Description</th>
  </tr>
  <tr class="rowA">
    <td>June 01, 2011</td>
    <td>Sed vestibulum blandit</td>
    <td>
    Come and check out demos of all the newest Tailspin Spyworks products and experience 
    them hands on.
    </td>
  </tr>
  <tr class="rowB">
    <td>November 28, 2011</td>
    <td>Spyworks Product Demo</td>
    <td>
    Come and check out demos of all the newest Tailspin Spyworks products and experience 
    them hands on.
    </td>
  </tr>
  <tr class="rowA">
    <td>November 23, 2011</td>
    <td>Spyworks Product Demo</td>
    <td>
     Come and check out demos of all the newest Tailspin Spyworks products and experience 
     them hands on.
    </td>
  </tr>
  <tr class="rowB">
    <td>November 21, 2011</td>
    <td>Spyworks Product Demo</td>
    <td>
    Come and check out demos of all the newest Tailspin Spyworks products and experience 
    them hands on.
    </td>
  </tr>
</table>

Recenze produktů

Nejprve přidáme tlačítko s odkazem na formulář, který můžeme použít k zadání recenze produktu.

<div class="SubContentHead">Reviews</div><br />
<a id="ReviewList_AddReview" href="ReviewAdd.aspx?productID=<%# Eval("ProductID") %>">
   <img id="Img2" runat="server" 
        src="~/Styles/Images/review_this_product.gif" alt="" />
</a>

Snímek obrazovky znázorňující umístění odkazu

Všimněte si, že v řetězci dotazu předáváme ID produktu.

Dále přidáme stránku s názvem ReviewAdd.aspx.

Na této stránce se použije ASP.NET AJAX Control Toolkit. Pokud jste to ještě neudělali, můžete si ho stáhnout z DevExpressu a pokyny k nastavení sady nástrojů pro použití se sadou Visual Studio najdete tady https://www.asp.net/learn/ajax-videos/video-76.aspx.

V režimu návrhu přetáhněte ovládací prvky a validátory ze sady nástrojů a sestavte formulář podobný následujícímu.

Snímek obrazovky s formulářem

Revize bude vypadat nějak takto.

<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</asp:ToolkitScriptManager>
<div class="ContentHead">Add Review - <asp:label id="ModelName" runat="server" /></div>
<div>
  <span class="NormalBold">Name</span><br />
  <asp:TextBox id="Name" runat="server" Width="400px" /><br />
  <asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator1" 
                              ControlToValidate="Name" 
                              Display="Dynamic" 
                              CssClass="ValidationError" 
                              ErrorMessage="'Name' must not be left blank."  /><br />
  <span class="NormalBold">Email</span><br />
  <asp:TextBox id="Email" runat="server" Width="400px" /><br />
  <asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator2" 
                              ControlToValidate="Email" Display="Dynamic" 
                              CssClass="ValidationError" 
                              ErrorMessage="'Email' must not be left blank." />
  <br /><hr /><br />
  <span class="NormalBold">Rating</span><br /><br />
  <asp:RadioButtonList ID="Rating" runat="server">
    <asp:ListItem value="5" selected="True" 
             Text='<img src="Styles/Images/reviewrating5.gif" alt=""> (Five Stars) '  />
    <asp:ListItem value="4" selected="True" 
             Text='<img src="Styles/Images/reviewrating4.gif" alt=""> (Four Stars) '  />
    <asp:ListItem value="3" selected="True" 
             Text='<img src="Styles/Images/reviewrating3.gif" alt=""> (Three Stars) '  />
    <asp:ListItem value="2" selected="True" 
             Text='<img src="Styles/Images/reviewrating2.gif" alt=""> (Two Stars) '  />
    <asp:ListItem value="1" selected="True" 
             Text='<img src="Styles/Images/reviewrating1.gif" alt=""> (One Stars) '  />
  </asp:RadioButtonList>
  <br /><hr /><br />
  <span class="NormalBold">Comments</span><br />
  <cc1:Editor ID="UserComment" runat="server" />
  <asp:RequiredFieldValidator runat="server" id="RequiredFieldValidator3" 
                              ControlToValidate="UserComment" Display="Dynamic" 
                              CssClass="ValidationError" 
                              ErrorMessage="Please enter your comment." /><br /><br />
  <asp:ImageButton ImageURL="Styles/Images/submit.gif" runat="server" 
                   id="ReviewAddBtn" onclick="ReviewAddBtn_Click" />
  <br /><br /><br />
</div>

Teď, když můžeme zadat recenze, můžeme tyto recenze zobrazit na stránce produktu.

Přidejte tuto značku na stránku ProductDetails.aspx.

<asp:ListView ID="ListView_Comments" runat="server" 
              DataKeyNames="ReviewID,ProductID,Rating" DataSourceID="EDS_CommentsList">
  <ItemTemplate>
    <tr>
      <td><%# Eval("CustomerName") %></td>
      <td>
        <img src='Styles/Images/ReviewRating_d<%# Eval("Rating") %>.gif' alt="">
        <br />
      </td>
      <td>
        <%# Eval("Comments") %>
      </td>
    </tr>
  </ItemTemplate>
  <AlternatingItemTemplate>
    <tr>
      <td><%# Eval("CustomerName") %></td>
      <td>
        <img src='Styles/Images/ReviewRating_da<%# Eval("Rating") %>.gif' alt="">
        <br />
      </td>
      <td><%# Eval("Comments") %></td>
    </tr>
  </AlternatingItemTemplate>
   <EmptyDataTemplate>
     <table runat="server">
       <tr><td>There are no reviews yet for this product.</td></tr>
     </table>
  </EmptyDataTemplate>
  <LayoutTemplate>
    <table runat="server">
      <tr runat="server">
        <td runat="server">
          <table ID="itemPlaceholderContainer" runat="server" border="1">
            <tr runat="server">
              <th runat="server">Customer</th>
              <th runat="server">Rating</th>
              <th runat="server">Comments</th>
             </tr>
             <tr ID="itemPlaceholder" runat="server"></tr>
           </table>
         </td>
       </tr>
       <tr runat="server">
         <td runat="server">
           <asp:DataPager ID="DataPager1" runat="server">
             <Fields>
               <asp:NextPreviousPagerField ButtonType="Button" 
                                           ShowFirstPageButton="True"
                                           ShowLastPageButton="True" />
             </Fields>
           </asp:DataPager>
         </td>
       </tr>
     </table>
  </LayoutTemplate>
</asp:ListView>
<asp:EntityDataSource ID="EDS_CommentsList" runat="server"  EnableFlattening="False" 
                       AutoGenerateWhereClause="True" 
                       EntityTypeFilter="" 
                       Select="" Where=""
                       ConnectionString="name=CommerceEntities" 
                       DefaultContainerName="CommerceEntities" 
                       EntitySetName="Reviews">
   <WhereParameters>
    <asp:QueryStringParameter Name="ProductID" QueryStringField="productID"  
                                               Type="Int32" />
  </WhereParameters>
</asp:EntityDataSource>

Při spuštění naší aplikace a přechodu na produkt se zobrazí informace o produktu včetně recenzí zákazníků.

Snímek obrazovky s recenzemi zákazníků

Ovládací prvek Oblíbené položky (vytváření uživatelských ovládacích prvků)

Abychom zvýšili prodeje na vašem webu, přidáme několik funkcí pro "sugestivní prodej" oblíbených nebo souvisejících produktů.

První z těchto funkcí bude seznam nejoblíbenějších produktů v našem katalogu produktů.

Vytvoříme "Uživatelský ovládací prvek", který zobrazí nejprodávanější položky na domovské stránce naší aplikace. Vzhledem k tomu, že se jedná o ovládací prvek, můžeme ho použít na libovolné stránce jednoduchým přetažením ovládacího prvku v návrháři sady Visual Studio na libovolnou stránku, která se nám líbí.

V průzkumníku řešení sady Visual Studio klikněte pravým tlačítkem na název řešení a vytvořte nový adresář s názvem Controls. I když to není nutné, pomůžeme nám udržet projekt uspořádaný vytvořením všech uživatelských ovládacích prvků v adresáři "Controls".

Klikněte pravým tlačítkem na složku ovládacích prvků a zvolte Nová položka:

Snímek obrazovky, který ukazuje, kde vybrat Novou položku

Zadejte název našeho ovládacího prvku PopularItems. Všimněte si, že přípona souboru pro uživatelské ovládací prvky je .ascx, nikoli .aspx.

Náš uživatelský ovládací prvek Oblíbené položky bude definován následujícím způsobem.

<%@ OutputCache Duration="3600" VaryByParam="None" %>
<div class="MostPopularHead">Our most popular items this week</div>
<div id="PanelPopularItems" runat="server">
  <asp:Repeater ID="RepeaterItemsList" runat="server">
    <HeaderTemplate></HeaderTemplate>
      <ItemTemplate>               
        <a class='MostPopularItemText' 
           href='ProductDetails.aspx?productID=<%# Eval("ProductId") %>'>
                                               <%# Eval("ModelName") %></a><br />              
      </ItemTemplate>
    <FooterTemplate></FooterTemplate>
  </asp:Repeater>
</div>

Tady používáme metodu, která se v této aplikaci ještě nepoužila. Používáme ovládací prvek repeater a místo ovládacího prvku zdroje dat vážeme ovládací prvek Repeater s výsledky LINQ to Entities dotazu.

V kódu na pozadí našeho ovládacího prvku to děláme následujícím způsobem.

using TailspinSpyworks.Data_Access;

protected void Page_Load(object sender, EventArgs e)
{
  using (CommerceEntities db = new CommerceEntities())
    {
    try
      {
      var query = (from ProductOrders in db.OrderDetails
                        join SelectedProducts in db.Products on ProductOrders.ProductID  
                        equals SelectedProducts.ProductID
                        group ProductOrders by new
                            {
                            ProductId = SelectedProducts.ProductID,
                            ModelName = SelectedProducts.ModelName
                            } into grp
                        select new
                            {
                            ModelName = grp.Key.ModelName,
                            ProductId = grp.Key.ProductId,
                            Quantity = grp.Sum(o => o.Quantity)
                            } into orderdgrp where orderdgrp.Quantity > 0 
                        orderby orderdgrp.Quantity descending select orderdgrp).Take(5);

                    RepeaterItemsList.DataSource = query;
                    RepeaterItemsList.DataBind(); 
      }
    catch (Exception exp)
      {
      throw new Exception("ERROR: Unable to Load Popular Items - " + 
                           exp.Message.ToString(), exp);
      }
    }
}

Všimněte si také tohoto důležitého řádku v horní části značky ovládacího prvku.

<%@ OutputCache Duration="3600" VaryByParam="None" %>

Vzhledem k tomu, že se nejoblíbenější položky nebudou měnit po minutách, můžeme přidat direktivu pro zlepšení výkonu aplikace. Tato direktiva způsobí, že kód ovládacích prvků se spustí pouze v případě, že vyprší platnost výstupu ovládacího prvku uloženého v mezipaměti. V opačném případě se použije verze výstupu ovládacího prvku uložená v mezipaměti.

Teď stačí přidat nový ovládací prvek na stránku Default.aspx.

Přetažením umístěte instanci ovládacího prvku do otevřeného sloupce formuláře Výchozí.

Snímek obrazovky, který ukazuje, kam umístit instanci ovládacího prvku

Když teď aplikaci spustíme, zobrazí se na domovské stránce nejoblíbenější položky.

Snímek obrazovky znázorňující, jak se na domovské stránce zobrazují nejoblíbenější položky

Také zakoupený ovládací prvek (uživatelské ovládací prvky s parametry)

Druhý uživatelský ovládací prvek, který vytvoříme, přesune sugestivní prodej na další úroveň přidáním kontextové specifičnosti.

Logika výpočtu prvních položek "Také zakoupených" je netriviální.

Náš ovládací prvek Také zakoupený vybere záznamy OrderDetails (dříve zakoupené) pro aktuálně vybrané ID produktu a získá ID objednávky pro každou nalezenou jedinečnou objednávku.

Pak vybereme produkty ze všech těchto objednávek a sečteme zakoupené množství. Seřadíme produkty podle tohoto součtu množství a zobrazíme prvních pět položek.

Vzhledem ke složitosti této logiky budeme tento algoritmus implementovat jako uloženou proceduru.

T-SQL pro uloženou proceduru je následující.

ALTER PROCEDURE dbo.SelectPurchasedWithProducts
 @ProductID int
AS
        SELECT  TOP 5 
    OrderDetails.ProductID,
    Products.ModelName,
    SUM(OrderDetails.Quantity) as TotalNum

FROM    
    OrderDetails
  INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID

WHERE   OrderID IN 
(
    /* This inner query should retrieve all orders that have contained the productID */
    SELECT DISTINCT OrderID 
    FROM OrderDetails
    WHERE ProductID = @ProductID
)
AND OrderDetails.ProductID != @ProductID 

GROUP BY OrderDetails.ProductID, Products.ModelName 

ORDER BY TotalNum DESC
RETURN

Všimněte si, že tato uložená procedura (SelectPurchasedWithProducts) existovala v databázi, když jsme ji zahrnuli do naší aplikace, a když jsme vygenerovali Model dat entit, zadali jsme, že kromě potřebných tabulek a zobrazení by měl datový model entity obsahovat i tuto uloženou proceduru.

Pokud chcete získat přístup k uložené proceduře z modelu Entity Data Model, musíme funkci importovat.

Poklikáním na model Entity Data Model v Průzkumníku řešení ho otevřete v návrháři a otevřete Prohlížeč modelů. Potom klikněte pravým tlačítkem na návrháře a vyberte Přidat import funkce.

Snímek obrazovky, který ukazuje, kde vybrat Přidat import funkce

Tím se otevře toto dialogové okno.

Snímek obrazovky s otevřeným dialogovým oknem

Vyplňte pole, jak vidíte výše, vyberte SelectPurchasedWithProducts a jako název importované funkce použijte název procedury.

Klikněte na OK.

Když to uděláme, můžeme jednoduše programovat proti uložené proceduře stejně jako jakoukoli jinou položku v modelu.

Takže v naší složce "Controls" vytvořte nový uživatelský ovládací prvek s názvem AlsoPurchased.ascx.

Značky pro tento ovládací prvek budou pro ovládací prvek PopularItems vypadat velmi povědomě.

<div>
<div class="MostPopularHead">
<asp:Label ID="LabelTitle" runat="server" Text=" Customers who bought this also bought:"></asp:Label></div>
<div id="PanelAlsoBoughtItems" runat="server">
    <asp:Repeater ID="RepeaterItemsList" runat="server">
       <HeaderTemplate></HeaderTemplate>
          <ItemTemplate>               
             <a class='MostPopularItemText' href='ProductDetails.aspx?productID=<%# Eval("ProductId") %>'><%# Eval("ModelName") %></a><br />              
          </ItemTemplate>
       <FooterTemplate></FooterTemplate>
    </asp:Repeater>
</div>
</div>

Rozdíl je v tom, že se výstup neukládají do mezipaměti, protože položky, které se mají vykreslit, se liší podle produktu.

ProductId bude "vlastností" ovládacího prvku.

private int _ProductId;

public int ProductId
{
get { return _ProductId ; }
set { _ProductId = Convert.ToInt32(value); }
}

V obslužné rutině události PreRender ovládacího prvku jsme chtěli udělat tři věci.

  1. Ujistěte se, že je nastavené ID produktu.
  2. Podívejte se, jestli nejsou koupené nějaké produkty s aktuálním produktem.
  3. Vypište některé položky podle 2.

Všimněte si, jak snadné je volat uloženou proceduru prostřednictvím modelu.

//--------------------------------------------------------------------------------------+
protected void Page_PreRender(object sender, EventArgs e)
{
  if (_ProductId < 1)
     {
     // This should never happen but we could expand the use of this control by reducing 
     // the dependency on the query string by selecting a few RANDOME products here. 
     Debug.Fail("ERROR : The Also Purchased Control Can not be used without 
                         setting the ProductId.");
     throw new Exception("ERROR : It is illegal to load the AlsoPurchased COntrol 
                                  without setting a ProductId.");
     }
      
  int ProductCount = 0;
  using (CommerceEntities db = new CommerceEntities())
    {
    try
      {
      var v = db.SelectPurchasedWithProducts(_ProductId);
      ProductCount = v.Count();
      }
    catch (Exception exp)
      {
      throw new Exception("ERROR: Unable to Retrieve Also Purchased Items - " + 
                                  exp.Message.ToString(), exp);
      }
    }

  if (ProductCount > 0)
     {
     WriteAlsoPurchased(_ProductId);              
     }
  else
     {
     WritePopularItems();
     }
}

Po zjištění, že jsou "také zakoupeny", můžeme jednoduše svázat opakovač s výsledky vrácenými dotazem.

//-------------------------------------------------------------------------------------+
private void WriteAlsoPurchased(int currentProduct)
{
  using (CommerceEntities db = new CommerceEntities())
        {
        try
          {
          var v = db.SelectPurchasedWithProducts(currentProduct);
          RepeaterItemsList.DataSource = v;
          RepeaterItemsList.DataBind();
          }
         catch (Exception exp)
          {
          throw new Exception("ERROR: Unable to Write Also Purchased - " + 
                                                          exp.Message.ToString(), exp);
          }
        }
}

Pokud nebyly koupené položky, jednoduše zobrazíme další oblíbené položky z našeho katalogu.

//--------------------------------------------------------------------------------------+
private void WritePopularItems()
{
  using (CommerceEntities db = new CommerceEntities())
    {
    try
      {
      var query = (from ProductOrders in db.OrderDetails
                   join SelectedProducts in db.Products on ProductOrders.ProductID 
                   equals SelectedProducts.ProductID
                   group ProductOrders by new
                         {
                         ProductId = SelectedProducts.ProductID,
                         ModelName = SelectedProducts.ModelName
                         } into grp
                   select new
                         {
                         ModelName = grp.Key.ModelName,
                         ProductId = grp.Key.ProductId,
                         Quantity = grp.Sum(o => o.Quantity)
                         } into orderdgrp
                   where orderdgrp.Quantity > 0
                   orderby orderdgrp.Quantity descending
                   select orderdgrp).Take(5);
                   
      LabelTitle.Text = "Other items you might be interested in: ";
      RepeaterItemsList.DataSource = query;
      RepeaterItemsList.DataBind();
      }
    catch (Exception exp)
      {
      throw new Exception("ERROR: Unable to Load Popular Items - " + 
                                                        exp.Message.ToString(), exp);
      }
    }
}

Chcete-li zobrazit také zakoupené položky, otevřete stránku ProductDetails.aspx a přetáhněte ovládací prvek AlsoPurchased z Průzkumníka řešení tak, aby se zobrazil na této pozici v přirážce.

<table  border="0">
  <tr>
     <td>
       <img src='Catalog/Images/<%# Eval("ProductImage") %>'  border="0" 
                                                   alt='<%# Eval("ModelName") %>' />
     </td>
     <td><%# Eval("Description") %><br /><br /><br />  
         <uc1:AlsoPurchased ID="AlsoPurchased1" runat="server" />                 
     </td>
   </tr>
</table>

Tím se vytvoří odkaz na ovládací prvek v horní části stránky ProductDetails.

<%@ Register src="Controls/AlsoPurchased.ascx" tagname="AlsoPurchased" tagprefix="uc1" %>

Vzhledem k tomu, že uživatelský ovládací prvek AlsoPurchased vyžaduje číslo ProductId, nastavíme vlastnost ProductID našeho ovládacího prvku pomocí příkazu Eval proti aktuální položce datového modelu stránky.

Snímek obrazovky se zvýrazněnou id produktu

Když teď sestavíme a spustíme a přejdeme k produktu, zobrazí se také zakoupené položky.

Snímek obrazovky znázorňující položky, které byly také zakoupeny