Ciao a tutti, sto cercando di eseguire una join tra 2 tabelle, in modo da recuperare un certo dato. Vi spiego la situazione:

Database con in tutti 3 tabelle relazionate tra loro (uno a molti): Gruppi --> Articoli --> Report.

Nella tabella articoli ho un campo int che prende il valore ID dei gruppi, nella tabella report ho un campo int che prende il valore ID della tabella Articoli. Quando eseguo una query, ad esempio sulla tabella report, non vorrei che venisse mostrato il valore del campo int collegato all'articolo ma vorrei che venisse mostrato il suo nome, questo dato si trova nella tabella articoli.

Ho pensato che la soluzione migliore potesse essere quella di creare una JOIN direttamente nella mia businessClass (dove gestisco tutti i vari metodi CRUD), ma non ci sono riuscito.

diciamo che ci sto provando... Ho creato il metodo nella business in questo modo:
 
     public static tbl_Articolo ArticoloReport(int idGruppo)
    {
        DatabaseReportEntities dc = new DatabaseReportEntities();
        var articoli = (from p in dc.tbl_Articolo join c in dc.tbl_GruppoArticoli on p.ID_Gruppo equals c.ID_Gruppo_Articoli where p.ID_Gruppo == idGruppo orderby p.Descrizione_Articolo select p).SingleOrDefault();
        return articoli;
    } 

Mentre nel code file:
 
     protected void GvReport_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        Label articolo = null;
        Label nascosta = null;
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            articolo = e.Row.FindControl("lblArticolo") as Label;
            nascosta = e.Row.FindControl("hiddenLbl") as Label;
        }
        if (articolo != null)
        {
            int nGruppo = Convert.ToInt32(e.Row.RowIndex);
            int nArticolo = Convert.ToInt32(nascosta.Text);
            var idGruppoHidden = BusinessClass.ArticoloReport(nArticolo);
            articolo.Text = idGruppoHidden.Descrizione_Articolo;
        }
...
... 

Come potete vedere il controllo label dove voglio mostrare il risultato della mia join si trova all'interno di un gridview.

Questa pova pero mi restituisce un risultato NullReferenceException, andando in debug ho visto che la variabile idGruppoHidden risulta null...

Avete qualche suggerimento?

Grazie.
Ricardo.

Creazione Siti Vicenza
Posizionamento Siti - SEO
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

ricardo78 ha scritto:

Questa pova pero mi restituisce un risultato NullReferenceException, andando in debug ho visto che la variabile idGruppoHidden risulta null...

Sì, SingleOrDefault restituirà null se la tua query LINQ non produce alcun elemento. La responsabile può essere la where, che impone p.ID_Gruppo == idGruppo. Se il valore di idGruppo non è presente su nessun articolo, allora la sequenza sarà vuota.
Oppure può dipendere anche dalla join, se p.ID_Gruppo ha un valore che non esiste nella tabella tbl_GruppoArticoli.

Dovresti usare il Sql Profiler per capire quale query viene effettivamente inviata al database. Oppure, se metti un breakpoint sulla riga della query LINQ, l'esecuzione si interromperà e tu potrai scoprire la query SQL poggiando il mouse sull'istruzione (vedi qui).

Se riesci a risolvere il problema, presta attenzione a queste altre cose.
  • Fai in modo che la nomenclatura sia coerente. Ad esempio, il parametro della funzione ArticoloReport si chiama "idGruppo", ma poi la stessa funzione viene invocata passandole una variabile "nArticolo". Dal codice non riesco a capire bene se passare "nArticolo" è stato un errore o se invece contiene effettivamente l'id di un gruppo.
  • La join non è necessaria. Se osservi la query LINQ, c'è una join tra tbl_Articolo e tbl_GruppoArticoli ma i campi di questa seconda tabella non vengono usati né nella where, né nella order by o nella select.
    Con Entity Framework è comunque raro usare una join tra le entità perché le relazioni puoi già mapparle nel modello concettuale come proprietà di navigazione. Ad esempio, quando ti servono tutti gli articoli di un gruppo, sarà sufficiente usare una proprietà gruppo.Articoli che ti permette, appunto, di "navigare" verso le sue entità correlate.
    Dietro le quinte, EF eseguirà una JOIN SQL sul database ma a noi non interessa perché questa complessità ci viene nascosta dietro la semplicità di utilizzo delle proprietà di navigazione.
  • Problema select n+1. Invocando il metodo ArticoloReport per ogni riga della gridView, vengono eseguite molte query al database e questo sistema non è molto efficiente per recuperare i dati. L'ideale sarebbe se il tuo metodo di business restituisse un IQueryable, in modo che la pagina aspx sia libera di decidere quali entità correlate includere e come proiettare il risultato.


buona domenica!
Modificato da BrightSoul il 09 giugno 2013 17.02 -

Enjoy learning and just keep making
Ciao BrightSoul, innanzitutto grazie per la risposta. Procedendo per ordine e a piccoli passi, ho sistemato la query al db (non era esatta) soo che ora mi restituisce questo errore:
La sequenza contiene più elementi 

Cosa vorrebbe dire esattamente secondo te? che contiene troppi dati?

Grazie,

Ricardo.

Creazione Siti Vicenza
Posizionamento Siti - SEO
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao Ricardo,

ricardo78 ha scritto:

tabelle relazionate tra loro (uno a molti): Gruppi --> Articoli

ok, questo significa che per in gruppo possono esserci più articoli.

Dunque quando cerchi un IDGruppo nella tabella articoli è possibile che ti saltino fuori molteplici records. La where nella tua query LINQ perciò non ti garantisce che ne venga fuori un solo elemento, anzi, è probabile il contrario.
where p.ID_Gruppo == idGruppo
Il metodo SingleOrDefault non è proprio idoneo in questo caso, perché se i risultati sono due o più, lancerà l'eccezione che hai appunto visto.
Usi SingleOrDefault quando ti aspetti che dalla query venga fuori al massimo un risultato, come quando cerchi un elemento per chiave primaria.

Dovresti usare FirstOrDefault che ti restituisce il primo elemento di una sequenza che può contenere molteplici elementi (oppure restituisce null se la sequenza era vuota).

ciao!
Modificato da BrightSoul il 10 giugno 2013 23.33 -

Enjoy learning and just keep making
Ciao BrightSoul, infatti ieri sera in letto prima di dormire ho pensato anch'io a modificarlo con FirstOrDefault. Ora la query sembra funzionare, solo che nel gridview continuo a vedere il numero ID invece che il nome preso dalla join, sicuramente devo cambiare il metodo rowDataBound, avresti qualche suggerimento?

Grazie ancora...

Creazione Siti Vicenza
Posizionamento Siti - SEO
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,
il corpo di rowDataBound sembra corretto ma per sicurezza metti un breakpoint alla prima istruzione e percorrine tutti i passi. Ad esempio, assicurati che la variabile articolo non sia null, cioè che il controllo Label venga effettivamente trovato perché quella potrebbe essere la causa per cui non vedi apparire il testo corretto.
Controlla anche il valore che assegni alla proprietà .Text, verifica che sia quello che ti aspetti di trovare.

Se non riesci a risolvere, posta il codice della GridView e del gestore dell'evento RowDataBound, nel caso fosse cambiato.

ciao!
Modificato da BrightSoul il 11 giugno 2013 22.27 -

Enjoy learning and just keep making
Ciao, allora ho capito perche non funziona, in pratica io ho 2 dropdown, la prima presenta i gruppi mentre la seconda gli articoli, dove la prima filtra la seconda in base al gruppo scelto.
Ho notato che in fase di inserimento nel db non viene salvato il valore scelto per l'articolo, andando a prendere soltanto il primo. Ho provveduto a commentare il codice (sotto riportato) e magicamente funziona...
    protected void selectGruppoChange(object sender, EventArgs e)
    {
        // Ottengo le info dalla ddl gruppo
        DropDownList gruppo = GvReport.FooterRow.FindControl("ddlGruppo") as DropDownList;
        int idGroup = Convert.ToInt32(gruppo.SelectedValue);
        // Eseguo la query sulla tabella articoli in base alla scelta
        var selezionaArticolo = BusinessClass.filtraArticoloPerGruppo(idGroup);
        if (selezionaArticolo.Count() != 0)
        {
            // Ottengo le info dalla ddl articoli ed assegno il risultato della query precedente
            DropDownList ddlArticolo = GvReport.FooterRow.FindControl("DdlArticoloNuovo") as DropDownList;
            ddlArticolo.Visible = true;
            ddlArticolo.DataSource = selezionaArticolo;
            ddlArticolo.DataTextField = "Descrizione_Articolo";
            ddlArticolo.DataValueField = "ID_Articolo";
            //ddlArticolo.Items.Insert(0, new System.Web.UI.WebControls.ListItem("- Scegli l'Articolo -"));
            ddlArticolo.DataBind();

            Label lblSelArt = GvReport.FooterRow.FindControl("lblSelArt") as Label;
            lblSelArt.Visible = true;
            lblSelArt.Text = "Scegli l'Articolo: ";

        }
        else
        {
            Label lblMsgNoResult = GvReport.FooterRow.FindControl("msgNoResult") as Label;
            lblMsgNoResult.Visible = true;
            lblMsgNoResult.Text = "Nessun articolo trovato<br /> per il gruppo scelto";

        }
    }

avete qualche idea su come rislvere?

Grazie..

Creazione Siti Vicenza
Posizionamento Siti - SEO
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,
prova a popolare la ddlArticolo usando il suo metodo Items.Add, così sarai libero di aggiungere l'elemento "Scegli articolo" in testa.

Cambia il seguente frammento di codice...
ddlArticolo.DataSource = selezionaArticolo;
ddlArticolo.DataTextField = "Descrizione_Articolo";
ddlArticolo.DataValueField = "ID_Articolo";
//ddlArticolo.Items.Insert(0, new System.Web.UI.WebControls.ListItem("- Scegli l'Articolo -"));
ddlArticolo.DataBind();


...in questo modo.
ddlArticolo.Items.Clear();
ddlArticolo.Items.Add(new ListItem("- Scegli l'articolo - ", ""));
foreach (var articolo in selezionaArticolo){
  ddlArticolo.Items.Add(new ListItem(articolo.Descrizione_Articolo, articolo.ID_Articolo))
}


ciao
Modificato da BrightSoul il 13 giugno 2013 23.21 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.