Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
von Joe Stagner
Tailspin Spyworks zeigt, wie außerordentlich einfach es ist, leistungsstarke, skalierbare Anwendungen für die .NET-Plattform zu erstellen. Es zeigt, wie Sie die großartigen neuen Features in ASP.NET 4 verwenden, um einen Online-Shop zu erstellen, einschließlich Shopping, Checkout und Verwaltung.
In dieser Lernprogrammreihe werden alle Schritte zum Erstellen der Tailspin Spyworks-Beispielanwendung beschrieben. Teil 7 fügt zusätzliche Features hinzu, z. B. Kontobewertung, Produktbewertungen sowie Benutzersteuerungen für "beliebte Artikel" und "auch gekauft."
Hinzufügen von Funktionen
Obwohl Benutzer unseren Katalog durchsuchen, Artikel in ihren Warenkorb legen und den Checkout-Prozess abschließen können, gibt es eine Reihe von unterstützenden Features, die wir zur Verbesserung unserer Website einschließen werden.
- Kontoüberprüfung (Aufgegebene Bestellungen auflisten und Details anzeigen.)
- Fügen Sie der Startseite kontextspezifische Inhalte hinzu.
- Fügen Sie ein Feature hinzu, mit dem Benutzer die Produkte im Katalog überprüfen können.
- Erstellen Sie ein Benutzersteuerelement, um beliebte Elemente anzuzeigen und dieses Steuerelement auf der Startseite zu platzieren.
- Erstellen Sie ein Benutzersteuerelement "Auch gekauft", und fügen Sie es der Produktdetailseite hinzu.
- Fügen Sie eine Kontaktseite hinzu.
- Fügen Sie eine Infoseite hinzu.
- Globaler Fehler
Kontoüberprüfung
Erstellen Sie im Ordner "Konto" zwei .aspx-Seiten, eine mit dem Namen OrderList.aspx und die andere mit dem Namen OrderDetails.aspx.
OrderList.aspx wird die GridView- und EntityDataSource-Steuerelemente ähnlich wie bisher nutzen.
<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>
Die EntityDataSource wählt Datensätze aus der Tabelle "Orders" aus, die nach dem Benutzernamen gefiltert sind (siehe WhereParameter), die wir in einer Sitzungsvariable festlegen, wenn sich der Benutzer einloggt.
Beachten Sie auch diese Parameter im HyperlinkField der GridView:
DataNavigateUrlFields="OrderID" DataNavigateUrlFormatString="~/Account/OrderDetails.aspx?OrderID={0}"
Diese geben den Link zur Ansicht "Bestelldetails" für jedes Produkt an, indem das Feld "OrderID" als QueryString-Parameter zur Seite OrderDetails.aspx angegeben wird.
OrderDetails.aspx
Wir verwenden ein EntityDataSource-Steuerelement, um auf die Bestellungen zuzugreifen, und ein FormView, um die Bestelldaten anzuzeigen. Mit einer anderen EntityDataSource und einer GridView werden alle Positionen der Bestellung angezeigt.
<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>
In der CodeBehind-Datei (OrderDetails.aspx.cs) haben wir zwei kleine Aufräumarbeiten.
Zuerst müssen wir sicherstellen, dass OrderDetails immer eine OrderId erhält.
protected void Page_Load(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(Request.QueryString["OrderId"]))
{
Response.Redirect("~/Account/OrderList.aspx");
}
}
Außerdem müssen wir die Bestellsumme aus den Positionen berechnen und anzeigen.
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");
}
}
Die Startseite
Fügen wir der seite Default.aspx statische Inhalte hinzu.
Zuerst erstelle ich einen Ordner "Inhalt" und darin einen Ordner "Bilder" (und ich werde ein Bild einfügen, das auf der Startseite verwendet werden soll.)
Fügen Sie im unteren Platzhalter der Default.aspx Seite das folgende Markup hinzu.
<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>
Produktbewertungen
Zuerst fügen wir eine Schaltfläche mit einem Link zu einem Formular hinzu, mit dem wir eine Produktüberprüfung eingeben können.
<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>
Beachten Sie, dass wir die ProductID in der Abfragezeichenfolge übergeben.
Als Nächstes fügen wir eine Seite mit dem Namen ReviewAdd.aspx
Diese Seite verwendet das ASP.NET AJAX Control Toolkit. Wenn Sie dies noch nicht getan haben, können Sie es von DevExpress herunterladen, und es gibt Anleitungen zum Einrichten des Toolkits für die Verwendung mit Visual Studio hier https://www.asp.net/learn/ajax-videos/video-76.aspx.
Ziehen Sie im Entwurfsmodus Steuerelemente und Validatoren aus der Toolbox, und erstellen Sie ein Formular wie die nachstehende.
Das Markup sieht ungefähr so aus.
<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>
Jetzt, da wir Rezensionen eingeben können, können diese Rezensionen auf der Produktseite angezeigt werden.
Fügen Sie dieses Markup zur ProductDetails.aspx Seite hinzu.
<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>
Wenn Sie unsere Anwendung jetzt ausführen und zu einem Produkt navigieren, werden die Produktinformationen einschließlich Kundenrezensionen angezeigt.
Steuerelement für beliebte Elemente (Erstellen von Benutzersteuerelementen)
Um den Umsatz auf Ihrer Website zu erhöhen, werden wir ein paar Funktionen hinzufügen, die den Suggestivverkauf von beliebten oder verwandten Produkten unterstützen.
Die erste dieser Features wird eine Liste der beliebtesten Produkte in unserem Produktkatalog sein.
Wir erstellen ein "Benutzersteuerelement", um die am häufigsten verkauften Artikel auf der Startseite unserer Anwendung anzuzeigen. Da dies ein Steuerelement ist, können wir es auf jeder Seite verwenden, indem wir das Steuerelement einfach im Visual Studio-Designer auf eine beliebige Seite ziehen und ablegen.
Klicken Sie im Projektmappen-Explorer von Visual Studio mit der rechten Maustaste auf den Projektmappennamen, und erstellen Sie ein neues Verzeichnis mit dem Namen "Steuerelemente". Obwohl dies nicht erforderlich ist, helfen wir, unser Projekt zu organisieren, indem wir alle unsere Benutzersteuerelemente im Verzeichnis "Steuerelemente" erstellen.
Klicken Sie mit der rechten Maustaste auf den Steuerelementordner, und wählen Sie "Neues Element" aus:
Geben Sie einen Namen für unser Steuerelement "PopularItems" an. Beachten Sie, dass die Dateierweiterung für Benutzersteuerelemente ASCX nicht .aspx ist.
Unser Benutzersteuerelement für beliebte Elemente wird wie folgt definiert.
<%@ 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>
Hier verwenden wir eine Methode, die wir noch nicht in dieser Anwendung verwendet haben. Wir verwenden das Repeater-Steuerelement und statt ein Datenquellensteuerelement zu verwenden, binden wir das Repeater-Steuerelement an die Ergebnisse einer LINQ to Entities-Abfrage.
Im Code-Behind unseres Steuerelements machen wir das wie folgt.
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);
}
}
}
Beachten Sie auch diese wichtige Zeile am oberen Rand des Markups unseres Steuerelements.
<%@ OutputCache Duration="3600" VaryByParam="None" %>
Da die beliebtesten Elemente nicht minutenweise geändert werden, können wir eine Caching-Direktive hinzufügen, um die Leistung unserer Anwendung zu verbessern. Diese Direktive bewirkt, dass der Steuerelementcode nur ausgeführt wird, wenn die zwischengespeicherte Ausgabe des Steuerelements abläuft. Andernfalls wird die zwischengespeicherte Version der Ausgabe des Steuerelements verwendet.
Jetzt müssen wir nur noch unser neues Steuerelement auf unserer Default.aspx-Seite einfügen.
Verwenden Sie Drag-and-Drop, um eine Instanz des Steuerelements in der freien Spalte unseres Standardformulars zu platzieren.
Wenn wir nun unsere Anwendung ausführen, werden auf der Startseite die am häufigsten verwendeten Elemente angezeigt.
"Auch gekauft"-Steuerelement (Benutzersteuerelemente mit Parametern)
Das zweite Benutzersteuerelement, das wir erstellen, wird suggestives Verkaufen auf die nächste Ebene heben, indem Kontextspezifität hinzugefügt wird.
Die Logik zum Berechnen der wichtigsten "Auch gekauften" Artikel ist nicht trivial.
Unser Steuerelement "Auch gekauft" wählt die OrderDetails-Datensätze der zuvor erworbenen Produkte für die aktuell ausgewählte ProductID aus und erfasst die OrderIDs für jede gefundene eindeutige Bestellung.
Zuerst wählen wir alle Produkte aus all diesen Bestellungen aus und summieren die gekauften Mengen. Wir sortieren die Produkte nach dieser Menge und zeigen die fünf obersten Artikel an.
Angesichts der Komplexität dieser Logik implementieren wir diesen Algorithmus als gespeicherte Prozedur.
Der T-SQL für die gespeicherte Prozedur lautet wie folgt.
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
Beachten Sie, dass diese gespeicherte Prozedur (SelectPurchasedWithProducts) in der Datenbank bereits vorhanden war, als wir sie in unsere Anwendung aufgenommen haben. Bei der Erstellung des Entitätsdatenmodells haben wir festgelegt, dass dieses Modell neben den benötigten Tabellen und Ansichten auch diese gespeicherte Prozedur enthalten soll.
Um auf die gespeicherte Prozedur aus dem Entitätsdatenmodell zuzugreifen, müssen wir die Funktion importieren.
Doppelklicken Sie im Projektmappen-Explorer auf das Entitätsdatenmodell, um es im Designer zu öffnen und den Modellbrowser zu öffnen, klicken Sie dann mit der rechten Maustaste auf den Designer, und wählen Sie "Funktionsimport hinzufügen" aus.
Dadurch wird dieses Dialogfeld geöffnet.
Füllen Sie die Felder wie oben aus, wählen Sie "SelectPurchasedWithProducts" aus, und verwenden Sie den Prozedurnamen für den Namen unserer importierten Funktion.
Klicken Sie auf "OK".
Nachdem wir dies getan haben, können wir einfach mit der gespeicherten Prozedur programmieren, so wie mit jedem anderen Element im Modell.
Erstellen Sie also in unserem Ordner "Steuerelemente" ein neues Benutzersteuerelement namens "AlsoPurchased.ascx".
Das Markup für dieses Steuerelement sieht dem PopularItems-Steuerelement sehr vertraut aus.
<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>
Der bemerkenswerte Unterschied besteht darin, dass die Ausgabe nicht zwischengespeichert wird, da das zu rendernde Element je nach Produkt unterschiedlich ist.
Die ProductId ist eine "Eigenschaft" für das Steuerelement.
private int _ProductId;
public int ProductId
{
get { return _ProductId ; }
set { _ProductId = Convert.ToInt32(value); }
}
Im PreRender-Ereignishandler des Steuerelements müssen wir drei Schritte durchführen.
- Stellen Sie sicher, dass die ProductID festgelegt ist.
- Überprüfen Sie, ob es Produkte gibt, die mit der aktuellen gekauft wurden.
- Geben Sie einige Elemente aus, wie in '2' festgelegt.
Beachten Sie, wie einfach es ist, die gespeicherte Prozedur über das Modell aufzurufen.
//--------------------------------------------------------------------------------------+
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();
}
}
Nachdem festgestellt wurde, dass 'auch gekauft' vorhanden sind, können wir den Repeater einfach an die Ergebnisse binden, die von der Abfrage zurückgegeben werden.
//-------------------------------------------------------------------------------------+
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);
}
}
}
Wenn es keine "auch gekauften" Artikel gab, zeigen wir einfach andere beliebte Artikel aus unserem Katalog an.
//--------------------------------------------------------------------------------------+
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);
}
}
}
Um die Elemente "Auch gekauft" anzuzeigen, öffnen Sie die Seite ProductDetails.aspx und ziehen Sie das AlsoPurchased-Steuerelement aus dem Lösungs-Explorer, sodass es an dieser Position im Markup angezeigt wird.
<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>
Dadurch wird ein Verweis auf das Steuerelement oben auf der Seite "ProductDetails" erstellt.
<%@ Register src="Controls/AlsoPurchased.ascx" tagname="AlsoPurchased" tagprefix="uc1" %>
Da für das Benutzersteuerelement "AlsoPurchased" eine ProductId-Nummer erforderlich ist, legen wir die ProductID-Eigenschaft unseres Steuerelements mithilfe einer Eval-Anweisung für das aktuelle Datenmodellelement der Seite fest.
Wenn wir jetzt erstellen und ausführen und zu einem Produkt navigieren, werden die Artikel "Auch gekauft" angezeigt.