Część 7. Dodawanie funkcji

Jan Stagner

Tailspin Spyworks ilustruje, w jaki sposób bardzo jest prosta, aby tworzyć zaawansowane, skalowalne aplikacje dla platformy .NET. W tym artykule przedstawiono sposób korzystania z doskonałych nowych funkcji w programie ASP.NET 4 do tworzenia sklepu online, w tym zakupów, wyewidencjonowywania i administrowania.

Ta seria samouczków zawiera szczegółowe informacje na temat wszystkich kroków podjętych w celu skompilowania przykładowej aplikacji Tailspin Spyworks. Część 7 dodaje dodatkowe funkcje, takie jak przegląd konta, przeglądy produktów i "popularne elementy" oraz "zakupione również" kontrolki użytkownika.

Dodawanie funkcji

Chociaż użytkownicy mogą przeglądać nasz katalog, umieszczać elementy w koszyku zakupów i dokończyć proces wyewidencjonowania, można dołączać do nich wiele funkcji pomocniczych w celu ulepszania naszej witryny.

  1. Przegląd konta (Lista zamówień umieszczonych i Wyświetl szczegóły).
  2. Dodaj zawartość specyficzną dla kontekstu do strony frontonu.
  3. Dodaj funkcję, aby umożliwić użytkownikom przeglądanie produktów w wykazie.
  4. Utwórz kontrolkę użytkownika, aby wyświetlić popularne elementy i umieścić tę kontrolkę na stronie frontonu.
  5. Utwórz "zakupione również" kontrolkę użytkownika i Dodaj ją do strony szczegółów produktu.
  6. Dodaj stronę kontaktu.
  7. Dodaj stronę informacje.
  8. Błąd globalny

Przegląd konta

W folderze "Account" Utwórz dwie strony. aspx o nazwie OrderList. aspx, a drugie o nazwie OrderDetails. aspx

OrderList. aspx będzie korzystać z kontrolek GridView i EntityDataSource, tak jak wcześniej.

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

Obiekt EntityDataSource wybiera rekordy z tabeli Orders filtrowanej według nazwy użytkownika (zobacz WhereParameter), która została ustawiona w zmiennej sesji podczas logowania użytkownika.

Zwróć uwagę na to, że te parametry HyperlinkField widoku GridView:

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

Określają one łącze do widoku szczegółów zamówienia dla każdego produktu, określając pole IDZamówienia jako parametr QueryString na stronie OrderDetails. aspx.

OrderDetails. aspx

Użyjemy kontrolki EntityDataSource do uzyskiwania dostępu do zamówień i FormView, aby wyświetlić dane zamówienia i inny obiekt EntityDataSource z elementem GridView, aby wyświetlić wszystkie elementy wiersza zamówienia.

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

W pliku związanym z kodem (OrderDetails.aspx.cs) mamy dwa małe bity dla gospodarstw domowych.

Najpierw musimy upewnić się, że OrderDetails zawsze otrzymuje IDZamówienia.

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

Musimy również obliczyć i wyświetlić sumę zamówień z elementów wiersza.

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

Strona główna

Dodajmy zawartość statyczną do domyślnej strony. aspx.

Najpierw utworzymy folder "Content" (zawartość), a w tym folderze obrazów (i dodamy obraz do użycia na stronie głównej).

Na dolny symbol zastępczy domyślnej strony. aspx Dodaj następujący znacznik.

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

Przeglądy produktu

Najpierw dodamy przycisk z linkiem do formularza, za pomocą którego możemy wprowadzić przegląd 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>

Zwróć uwagę, że przekazujemy klucz ProductID w ciągu zapytania

Dodaj stronę o nazwie ReviewAdd. aspx

Ta strona będzie używać zestawu narzędzi ASP.NET AJAX Control. Jeśli jeszcze tego nie zrobiono, możesz pobrać go z subskrypcja DevExpress i uzyskać wskazówki dotyczące konfigurowania zestawu narzędzi do użycia z programem Visual Studio tutaj https://www.asp.net/learn/ajax-videos/video-76.aspx.

W trybie projektowania przeciągnij kontrolki i moduły walidacji z przybornika i Utwórz formularz podobny do przedstawionego poniżej.

Oznakowanie będzie wyglądać podobnie do tego.

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

Teraz, gdy możemy wprowadzić przeglądy, umożliwia wyświetlenie tych przeglądów na stronie produkt.

Dodaj tę adiustację do strony 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>

Uruchomienie naszej aplikacji teraz i przechodzenie do produktu powoduje wyświetlenie informacji o produkcie, w tym przeglądów klientów.

Kontrolka popularne elementy (Tworzenie formantów użytkownika)

Aby zwiększyć sprzedaż w witrynie sieci Web, dodamy kilka funkcji do popularnych lub powiązanych produktów "z sugestiami".

Pierwszy z tych funkcji będzie listą bardziej popularnego produktu w naszym katalogu produktów.

Utworzymy "kontrolkę użytkownika" w celu wyświetlenia najważniejszych elementów sprzedaży na stronie głównej naszej aplikacji. Ponieważ będzie to formant, można go używać na dowolnej stronie przez przeciąganie i upuszczanie kontrolki w projektancie programu Visual Studio na dowolną stronę, którą lubimy.

W Eksploratorze rozwiązań programu Visual Studio kliknij prawym przyciskiem myszy nazwę rozwiązania i Utwórz nowy katalog o nazwie "Controls" (kontrolki). Chociaż nie jest to konieczne, pomożemy nam zorganizować projekt, tworząc wszystkie formanty użytkownika w katalogu "Controls".

Kliknij prawym przyciskiem myszy folder Controls i wybierz pozycję "nowy element":

Określ nazwę naszej kontroli "PopularItems". Należy zauważyć, że rozszerzenie pliku dla kontrolek użytkownika to. ascx not. aspx.

Nasze popularne elementy formant użytkownika zostanie zdefiniowany w następujący sposób.

<%@ 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>

W tym miejscu korzystamy z metody, która nie została jeszcze użyta w tej aplikacji. Używamy formantu wzmacniania, a nie za pomocą kontroli źródła danych, aby powiązać formant wzmacnia z wynikami zapytania LINQ to Entitiesowego.

W kodzie związanym z naszym formantem Wykonujemy poniższe czynności.

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

Pamiętaj również, że ten ważny wiersz znajduje się w górnej części znacznika kontrolki.

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

Ze względu na to, że najpopularniejsze elementy nie zostaną zmienione na minutę, możemy dodać dyrektywę aching, aby zwiększyć wydajność naszej aplikacji. Ta dyrektywa spowoduje, że kod kontrolny zostanie wykonany tylko po wygaśnięciu zbuforowanego danych wyjściowych formantu. W przeciwnym razie zostanie użyta buforowana wersja danych wyjściowych kontrolki.

Teraz wszystko, co należy zrobić, obejmuje nasz nowy formant na stronie Default. aspx.

Użyj przeciągania i upuszczania, aby umieścić wystąpienie kontrolki w kolumnie Otwórz w naszym formularzu domyślnym.

Teraz podczas uruchamiania naszej aplikacji na stronie głównej są wyświetlane najbardziej popularne elementy.

Kontrolka "kupione również" (kontrolki użytkownika z parametrami)

Druga kontrolka użytkownika, którą utworzymy, zajmie się sugerowanym sprzedażą do następnego poziomu, dodając specyficzność kontekstu.

Logika służąca do obliczania elementów Top "zakupionych" jest nieprosta.

Nasz "zakupiony" formant wybierze rekordy OrderDetails (wcześniej zakupione) dla aktualnie wybranego identyfikatora ProductID i odnalezienie identyfikatorów unikatowych dla każdego unikatowego zamówienia.

Następnie wybierzemy pozycję Al produkty ze wszystkich tych zamówień i zasumujesz zakupione ilości. Posortujemy produkty według tej ilości sum i wyświetlamy pięć pierwszych elementów.

Ze względu na złożoność tej logiki zaimplementujmy ten algorytm jako procedurę składowaną.

Język T-SQL dla procedury składowanej jest następujący:

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

Należy zauważyć, że ta procedura składowana (SelectPurchasedWithProducts) istniała w bazie danych, gdy została ona uwzględniona w naszej aplikacji, a w przypadku wygenerowania Entity Data Model określić, że oprócz tabel i widoków, które są niezbędne, Entity Data Model powinna zawierać tę procedurę składowaną.

Aby uzyskać dostęp do procedury składowanej z Entity Data Model musimy zaimportować funkcję.

Kliknij dwukrotnie Entity Data Model w Eksploratorze rozwiązań, aby otworzyć go w Projektancie i otworzyć przeglądarkę modelu, a następnie kliknij prawym przyciskiem myszy w Projektancie i wybierz pozycję "Dodaj Import funkcji".

Spowoduje to otwarcie tego okna dialogowego.

Wypełnij pola, jak widać powyżej, wybierając "SelectPurchasedWithProducts" i użyj nazwy procedury dla nazwy naszej funkcji zaimportowanej.

Kliknij przycisk "OK".

Po wykonaniu tej czynności można po prostu programować w odniesieniu do procedury składowanej, ponieważ możemy użyć dowolnego innego elementu w modelu.

W naszym folderze "Controls" Utwórz nową kontrolkę użytkownika o nazwie AlsoPurchased. ascx.

Znaczniki dla tej kontrolki będą wyglądały na bardzo zaznajomione z kontrolką PopularItems.

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

Istotną różnicą jest to, że nie buforowanie danych wyjściowych, ponieważ element, który ma być renderowany, będzie różnić się w zależności od produktu.

Identyfikator ProductId będzie "właściwości" kontrolki.

private int _ProductId;

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

W programie obsługi zdarzeń zdarzenia PreRender EED do wykonania trzy rzeczy.

  1. Upewnij się, że identyfikator ProductID jest ustawiony.
  2. Sprawdź, czy istnieją jakieś produkty, które zostały zakupione w ramach bieżącego.
  3. Wyprowadzanie niektórych elementów jako określonych w #2.

Zwróć uwagę na to, jak łatwo jest wywołać procedurę składowaną za pomocą 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 ustaleniu, że istnieje również "zakup", można po prostu powiązać wzmacniak z wynikami zwróconymi przez zapytanie.

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

Jeśli nie zostały jeszcze zakupione elementy, po prostu wyświetlamy inne popularne elementy z naszego 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);
      }
    }
}

Aby wyświetlić elementy "kupione również", Otwórz stronę ProductDetails. aspx i przeciągnij kontrolkę AlsoPurchased z Eksploratora rozwiązań, aby była wyświetlana w tym miejscu w znaczniku.

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

Spowoduje to utworzenie odwołania do kontrolki w górnej części strony ProductDetails.

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

Ponieważ kontrolka użytkownika AlsoPurchased wymaga numeru ProductId, ustawimy Właściwość ProductID formantu przy użyciu instrukcji eval względem bieżącego elementu modelu danych strony.

Po skompilowaniu i uruchomieniu teraz i przejściu do produktu zobaczysz "kupione również elementy".