in

DotNetSide

Dot Net South Italy Developers User Group

Tips

July 2006 - Posts

  • Caricare dinamicamente uno User Control

    Autore: Mario Ferrante

    Normalmente quando in una pagina aspx sono presenti User Controls, essi devono essere “registrati” nella direttiva @Register della pagina che lo contiene:

    <%@ Register Src="[path dello User Control]" TagName="myUC" TagPrefix="uc1" %>

    Quindi possono essere richiamati in qualsiasi parte del corpo della pagina attraverso una sintassi di questo tipo:

    <uc1:myUC ID="myUC1" runat="server" />

    L’IDE di Visual Studio esegue tutto questo lavoro automaticamente, basta trascinare lo User Control appena costruito dalla finestra Solution Explorer all’interno della pagina per vedere comparire la direttiva Register e tutto il resto.

    Tuttavia possono capitare situazioni in cui abbiamo la necessità di caricare degli User Control dinamicamente in base ad alcuni eventi, tipo il cambio di valore della Querystring.
    Ad esempio, supponiamo di avere tre User Control per gestire l’aggiunta, la visualizzazione e la modifica di clienti in un’applicazione di Commercio Elettronico.
    Mettiamo caso che nella pagina customers.aspx, in base al valore della chiave action della querystring, dobbiamo caricare l’User Control appropriato.
    La pagina
    customers.aspx conterrà sempilecemente un controllo Panel:

    1    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="customers.aspx.cs" Inherits="customers" %>
    2
    3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    4
    5 <html xmlns="http://www.w3.org/1999/xhtml" >
    6 <head runat="server">
    7 <title>Untitled Page</title>
    8 </head>
    9 <body>
    10 <form id="form1" runat="server">
    11 <div>
    12 <asp:Panel ID="Panel1" runat="server" Width="80%">
    13 </asp:Panel>
    14 </div>
    15 </form>
    16 </body>
    17 </html>

    Nel Code Behind associato alla pagina, customers.aspx.cs avremo:

    1    protected void Page_Load(object sender, EventArgs e)
    2 {
    3 System.Web.UI.Control myUserControl;
    4 string action = Request.QueryString["action"];
    5 switch (action) {
    6 case "add":
    7 myUserControl = LoadControl("../Controls/addCustomer.ascx");
    8 break;
    9 case "update":
    10 myUserControl = LoadControl("../Controls/updateCustomer.ascx");
    11 break;
    12 case "view":
    13 myUserControl = LoadControl("../Controls/viewCustomers.ascx");
    14 break;
    15 default:
    16 myUserControl = LoadControl("../Controls/homeCustomers.ascx");
    17 break;
    18 }
    19 this.Panel1.Controls.Add(myUserControl);
    20 }

    Nell’esempio, il caricamento dinamico dello UC viene inserito nell’evento Load della pagina in base al valore assunto da una querystring, ma è possibile eseguire questa azione all’interno di altri eventi quali il Click di una Button e così via.

    Da notare che nella pagina aspx non vi è traccia alcuna della direttiva @Register.

     
    Posted Jul 14 2006, 09:42 AM by VitoA with no comments
    Filed under:
  • Logiche di business mediante trigger

    Autore: Francesco Quaratino

    I trigger sono, talvolta, l'estremo rimedio a problemi altrimenti insormontabili. Anche se Microsoft tende a scoraggiarne l'uso, in alcuni casi è bene prenderli in seria  considerazione, come, per esempio, l'implementazione di logiche aziendali complesse che l'integrità referenziale non è in grado di supportare.

    Questo tips presenta un caso concreto in cui l'uso dei trigger favorisce le performance di un'applicazione. Mi riferisco a un'applicazione gestionale abbastanza comune, legata alla gestione acquisti di un prodotto: il calcolo dell'ultimo costo d'acquisto del prodotto.

    Conoscere il costo ultimo di un prodotto è di fondamentale importanza per riordinarlo dal fornitore più conveniente, così come per fissarne un prezzo di vendita.

    Spesso i progettisti software decidono di far calcolare il costo ultimo nel momento stesso in cui viene richiesto dall'utente, motivando tale scelta col fatto che si tratta di un “campo calcolabile”, il quale non necessità di essere ospitato permanentemente nel database (e di conseguenza trattato in fase di inserimento/modifica/cancellazione).

    Se, però, questa decisione non è supportata da un'analisi preventiva del carico di lavoro a cui sarà soggetta l'applicazione, la procedura che si occupa di calcolare il costo ultimo, rischia di diventare il collo di bottiglia di funzionalità vitali della nostra applicazione (come, per esempio, la fase di riordino dei prodotti la cui giacenza va sotto la soglia della scorta minima  prestabilita, che in alcune realtà commerciali è un'operazione svolta giornalmente e molto onerosa da un punto di vista delle risorse di sistema impegnate).

    Supponiamo quindi di trovarci di fronte al seguente database, che raccoglie gli ordini a fornitore di prodotti di natura non specificata:





    Per l'esattezza, ecco i significati delle tabelle:

    ●    [OrderHeader]: i dati generali degli ordini a fornitore
    ●    [OrderDetail]: i dati dettagliati dei prodotti ordinati
    ●    [Fornitore]: i dati dei fornitori che ci riforniscono i nostri depositi
    ●    [Prodotto]: i dati dei prodotti ordinabili ai ns fornitori

    Con questi dati a disposizione, ricavare - mediante Transact-SQL - il prezzo ultimo del prodotto per un particolare fornitore, significa scrivere questo codice:

    1    DECLARE 
    2 @codice_prodotto INT,
    3 @codice_fornitore INT
    4
    5 SET
    @codice_fornitore = 1
    6 SET @codice_prodotto = 3
    7
    8
    9 SELECT TOP 1
    10 prezzo_acquisto
    11 FROM
    12 OrderHeader H
    13 INNER JOIN
    14 OrderDetail D
    15 ON
    16 D.idHeader = H.id
    17 WHERE
    18 codice_prodotto = @codice_prodotto
    19 AND
    20 codice_fornitore = @codice_fornitore
    21 ORDER BY
    22 data_ordine
    23 DESC


    Questa query risolve il problema restituendo il dato desiderato, ma in presenza di migliaia di ordini tale risultato potrebbe giungere in tempi troppo lunghi per la pazienza di utente. Proviamo a risolvere l'eventuale problema di performance “materializzando” il campo calcolabile del prezzo ultimo, attraverso la tabella [CostoUltimoProdottoFornitore]:





    Quindi gestiamo la nuova tabella attraverso il seguente trigger creato sulla tabella [OrderDetail] che scatta in fase di inserimento e modifica:

    1    CREATE TRIGGER tr_insert_update_costo_ultimo
    2 ON dbo.OrderDetail
    3 AFTER
    4 INSERT, UPDATE
    5 AS
    6
    7 IF
    @@ROWCOUNT = 0
    8 RETURN
    9
    10 /* verifico l'esistenza nella tabella [CostoUltimoProdottoFornitore] della riga
    11 relativa al prodotto inserito o aggiornato nell'ordine */

    12 IF EXISTS
    13 (
    14 SELECT *
    15 FROM CostoUltimoProdottoFornitore C
    16 INNER JOIN Inserted i
    17 ON C.codice_prodotto = i.codice_prodotto
    18 INNER JOIN OrderHeader H
    19 ON H.id = i.idHeader
    20 AND H.codice_fornitore = C.codice_fornitore
    21 )
    22 /* ne aggiorno il costo ultimo */
    23 UPDATE C
    24 SET costo_ultimo = i.prezzo_acquisto
    25 FROM CostoUltimoProdottoFornitore C
    26 INNER JOIN Inserted i
    27 ON C.codice_prodotto = I.codice_prodotto
    28 INNER JOIN OrderHeader H
    29 ON H.id = i.idHeader
    30 AND H.codice_fornitore = C.codice_fornitore
    31 ELSE
    32 /* inserisco la riga corrispondete */
    33 INSERT INTO CostoUltimoProdottoFornitore
    34 ( codice_prodotto, codice_fornitore, costo_ultimo)
    35 SELECT i.codice_prodotto, H.codice_fornitore, i.prezzo_acquisto
    36 FROM Inserted i
    37 INNER JOIN OrderHeader H
    38 ON H.id = i.idHeader
    39
    40 RETURN
    41 GO


    In realtà, la gestione della tabella  [CostoUltimoProdottoFornitore] non si esaurisce con questo trigger. In genere, infatti, occorrerebbe trattare l'eventuale cancellazione del prodotto dall'ordine, così come la modifica del fornitore dell'ordine e tutte gli altri eventi che le applicazioni costruite sul database sono in grado di attivare. Potrebbe essere opportuno anche strutturare diversamente la tabella in modo da conservare un numero ragionevole di costi ultimi e non uno soltanto come nel nostro esempio, la cui complessità è stata volutamente mantenuta ridotta.

    N.B.: scarica lo script allegato per generare il database e il trigger di esempio.

     
     
      


     
    Posted Jul 12 2006, 08:57 AM by VitoA with no comments
    Filed under:
Powered by Community Server (Commercial Edition), by Telligent Systems