|
Nous avons souvent à utiliser une GridView qui affiche une
liste de lignes provenant directement de nos données préférées. Mais voilà,
comme d’habitude nous cherchons à aller vite, alors qu'est ce qui se passe derrière ? Je vais ici n’utiliser que les
Wizards pour comparer ce qui se passe derrière tout ça.
Pour ce test, j’utilise la base AdventureWorks sur SQL
Server 2008 R2 et ASP.NET 4. Le but étant d’afficher la liste des contacts
(Title, FirstName, MiddleName & LastName), d’avoir un pager et de pouvoir
trier. Pour ceci, je vais utiliser soit un SqlDataSource ou un LinqDataSource
ou un EntityDataSource.
SqlDataSource
On précise ici simplement notre SELECT et le SqlDataSource s’occupe
de tout.
|
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SqlDataSource.aspx.cs" Inherits="SqlDataSource"
%>
<!DOCTYPE html
PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>SqlDataSource</title>
</head>
<body>
<form id="form1" runat="server">
<asp:SqlDataSource ID="x_oSqlDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:AdventureWorks %>"
SelectCommand="SELECT Title, FirstName, MiddleName, LastName FROM
Person.Contact">
</asp:SqlDataSource>
<div>
<asp:GridView ID="x_grdContacts" runat="server" AllowPaging="True" AllowSorting="True"
AutoGenerateColumns="False" CellPadding="4" DataSourceID="x_oSqlDataSource" ForeColor="#333333"
GridLines="None">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="MiddleName" HeaderText="MiddleName" SortExpression="MiddleName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
</Columns>
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C"
/>
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE"
/>
</asp:GridView>
</div>
</form>
</body>
</html>
|
Voici ce que le profiler SQL nous indique comme activité :
Alors oui nous retrouvons notre select « SELECT Title,
FirstName, MiddleName, LastName FROM Person.Contact », mais par contre
comment fais ce petit malin pour le paging et le tri ? Tout simplement en
récupérant tous les enregistrements et en faisant le traitement côté client.
LinqDataSource
Avant de faire la page, on doit créer notre fichier « *.dbml »
et faire un mapping. Ensuite nous pouvons utiliser notre LinqDataSource.
|
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LinqDataSource.aspx.cs" Inherits="LinqDataSource"
%>
<!DOCTYPE html
PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>LINQDataSource</title>
</head>
<body>
<form id="form1" runat="server">
<asp:LinqDataSource ID="x_oLinqDataSource" runat="server"
ContextTypeName="LinqAdventureWorksDataContext"
EntityTypeName="" Select="new (Title, FirstName, MiddleName, LastName)"
TableName="Contacts">
</asp:LinqDataSource>
<div>
<asp:GridView ID="x_grdContacts" runat="server" AllowPaging="True" AllowSorting="True"
AutoGenerateColumns="False" CellPadding="4" DataSourceID="x_oLinqDataSource"
ForeColor="#333333" GridLines="None">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:BoundField DataField="Title" HeaderText="Title" ReadOnly="True" SortExpression="Title" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" ReadOnly="True" SortExpression="FirstName" />
<asp:BoundField DataField="MiddleName" HeaderText="MiddleName" ReadOnly="True" SortExpression="MiddleName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" ReadOnly="True" SortExpression="LastName" />
</Columns>
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C"
/>
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE"
/>
</asp:GridView>
</div>
</form>
</body>
</html>
|
Nous retrouvons du basique, notre contexte, table et contenu
du « SELECT ». Que trouvons-nous côté SQL ?
Ici nous retrouvons des lots de deux requêtes :
|
SELECT COUNT(*) AS [value]
FROM [Person].[Contact] AS [t0]
|
|
exec sp_executesql N'SELECT [t1].[Title],
[t1].[FirstName], [t1].[MiddleName], [t1].[LastName]
FROM (
SELECT ROW_NUMBER() OVER
(ORDER BY [t0].[Title], [t0].[FirstName], [t0].[MiddleName], [t0].[LastName])
AS [ROW_NUMBER], [t0].[Title], [t0].[FirstName], [t0].[MiddleName],
[t0].[LastName]
FROM [Person].[Contact] AS
[t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]',N'@p0 int,@p1 int',@p0=0,@p1=10
|
Le LinqDataSource demande à chaque affichage le nombre d’enregistrements,
ensuite on rapatrie uniquement les enregistrements requis grâce à l’utilisation
de ROW_NUMBER() apparu avec SQL Server 2005. Notons tout de même qu’un tri sur
toutes les colonnes est systématiquement demandé.
EntityDataSource
Avant de faire la page, on doit créer notre fichier « *.edmx »
et faire un mapping. Ensuite nous pouvons utiliser notre EntityDataSource.
Rien que du traditionnel ici, une petite astuce pour que le
tri fonctionne, il faut bien définir « AutoGenerateOrderByClause »
à « true » ainsi que la section « OrderByParameters ».
|
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="EntityDataSource.aspx.cs"
Inherits="EntityDataSource" %>
<!DOCTYPE html
PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>EntityDataSource</title>
</head>
<body>
<form id="form1" runat="server">
<asp:EntityDataSource ID="x_oEntityDataSource" runat="server"
AutoGenerateOrderByClause="True" ConnectionString="name=EntityAdventureWorks"
DefaultContainerName="EntityAdventureWorks" EnableFlattening="False"
EntitySetName="Contact"
EntityTypeFilter="Contact"
Select="it.[Title], it.[FirstName], it.[MiddleName],
it.[LastName]">
<OrderByParameters>
<asp:Parameter DefaultValue="Title" />
</OrderByParameters>
</asp:EntityDataSource>
<div>
<asp:GridView ID="x_grdContacts" runat="server" AllowPaging="True" AllowSorting="True"
CellPadding="4" DataSourceID="x_oEntityDataSource" ForeColor="#333333"
GridLines="None"
AutoGenerateColumns="False">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:BoundField DataField="Title" HeaderText="Title" ReadOnly="True" SortExpression="Title" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" ReadOnly="True" SortExpression="FirstName" />
<asp:BoundField DataField="MiddleName" HeaderText="MiddleName" ReadOnly="True" SortExpression="MiddleName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" ReadOnly="True" SortExpression="LastName" />
</Columns>
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C"
/>
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE"
/>
</asp:GridView>
</div>
</form>
</body>
</html>
|
Voici ce que le Profiler SQL nous apporte :
Nous retrouvons ici la même mécanique que notre
LinqDataSource, c’est-à-dire, une requête pour connaître le nombre d’enregistrements
et une autre pour rapatrier le nombre d’enregistrement de la page à afficher.
Par contre, le tri est appliqué uniquement sur la colonne demandée et non
toutes les colonnes comme la LinqDataSource. Voici les requêtes
|
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM
[Person].[Contact] AS
[Extent1]
) AS [GroupBy1]
|
|
SELECT TOP (10)
[Project1].[C1] AS [C1],
[Project1].[Title] AS [Title],
[Project1].[FirstName] AS
[FirstName],
[Project1].[MiddleName] AS
[MiddleName],
[Project1].[LastName] AS
[LastName]
FROM ( SELECT
[Project1].[Title] AS
[Title], [Project1].[FirstName]
AS [FirstName],
[Project1].[MiddleName] AS [MiddleName],
[Project1].[LastName] AS [LastName], [Project1].[C1] AS [C1], row_number() OVER (ORDER BY [Project1].[Title]
ASC) AS [row_number]
FROM ( SELECT
[Extent1].[Title]
AS [Title],
[Extent1].[FirstName]
AS [FirstName],
[Extent1].[MiddleName]
AS [MiddleName],
[Extent1].[LastName]
AS [LastName],
1 AS
[C1]
FROM
[Person].[Contact] AS
[Extent1]
) AS
[Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[Title] ASC
|
Bien que syntaxiquement très différente de celles de notre
LinqDataSource, ces requêtes sont sémantiquement identiques. En effet, elles
ont exactement le même plan d’exécution et temps d’exécution.
Conclusion
Tout d’abord, n’oublions pas le nombre de maquettes qui finissent en ligne trop rapidement. Dans ce sens, il faut oublier le SqlDataSource sauf à avoir une interdiction formelle à LinqDataSource ou EntityDataSource. Sinon, l’utilisation de LinqDataSource ou EntityDataSource peut se faire selon les préférences ou affinités de chacun.
|