Avatar billede c-lund Nybegynder
20. februar 2012 - 20:11 Der er 5 kommentarer

Menu med rekursiv funktion - Stored Procedure

Hej

Jeg har lige nu en ASP menu der bliver hentet fra en database.

DB'en: (MsSql)
Id - Ref_Id - Navn - Order

Når jeg henter menu ud køre jeg bare en funktion i en funktion, hvilket er ret langsomt. se eks. nedenfor.

Tænker om man kan lave det på en smartere måde, måske i har nogle gode idéer?
Har hørt nogle snakke om, at man kan lave det med en Stored procedure, har i nogle forslag til det?

Håber i kan hjælpe så jeg igen kan få liv i sitet.
--------------------------------------
    <ul>
            <%
                Function BygHovedMenu(MenuID)
                    UnderSQL = "SELECT * FROM Live_Menu_" & MenuNavn & " WHERE Ref_Id = ? ORDER BY Nummer"
                    set cmd = Server.CreateObject("ADODB.Command")
                    set cmd.ActiveConnection = Conn
                    cmd.CommandType = adCmdText
                    cmd.CommandText = UnderSQL       
                    cmd.Parameters.Append cmd.CreateParameter("Ref_Id", adInteger, adParamInput, 4, MenuID)
                    set UnderRS = cmd.Execute()

                    Response.write("<ul>")
                    While Not UnderRS.EOF
                                   
                        Response.Write("<li>")
                        If CountSubsH(UnderRS("ID")) > 0 Then
                            Response.Write("" & UnderRS("Navn") & "")
                           
                            BygHovedMenu UnderRS("ID")
                        Else
                            Response.Write("" & UnderRS("Navn") & "")
                        End If
                        Response.Write("</li>")
                       
                        UnderRS.MoveNext
                    Wend
                    Response.write("</ul>")
                End Function
           
                Function CountSubsH(MenuID)
                    CountSQL = "SELECT Count(*) as CountSubs FROM Live_Menu_" & MenuNavn & " WHERE Ref_Id = ?"
                    set cmd = Server.CreateObject("ADODB.Command")
                    set cmd.ActiveConnection = Conn
                    cmd.CommandType = adCmdText
                    cmd.CommandText = CountSQL
                    cmd.Parameters.Append cmd.CreateParameter("Ref_Id", adInteger, adParamInput, 4, MenuID)
                    set CountRS = cmd.Execute()
                   
                    CountSubsH = CountRS("CountSubs")
                End Function


                SQL = "SELECT * FROM Live_Menu_" & MenuNavn & " WHERE Ref_Id = ? ORDER BY Nummer"
                set cmd = Server.CreateObject("ADODB.Command")
                set cmd.ActiveConnection = Conn
                cmd.CommandType = adCmdText
                cmd.CommandText = SQL
                cmd.Parameters.Append cmd.CreateParameter("Ref_Id", adInteger, adParamInput, 4, "0")
                set RS = cmd.Execute()

                If RS.BOF AND RS.EOF Then
                Else
                    While Not RS.EOF
                                               
                        Response.write("<li>")

                        If CountSubsH(RS("ID")) > 0 Then       
                            Response.Write("" & RS("Navn") & "")
                           
                            BygHovedMenu RS("Id")
                        Else
                            Response.Write("" & RS("Navn") & "")
                        End if

                        Response.write("</li>")
                    RS.MoveNext
                    Wend
                End If
            %>
            </ul>
Avatar billede claes57 Ekspert
20. februar 2012 - 20:43 #1
alle function skal placeres som det første på hele sidens kode
<%
functions...
%>
resten uændret
Avatar billede softspot Forsker
20. februar 2012 - 22:42 #2
Læs hele tabellen på een gang og opbyg den bagefter. Du kan dermed nøjes med ét kald til databasen.

Du kan f.eks. bruge rs.GetRows til at læsse data over i et 2-dimensionelt array, der modsvarer den tabel du henter (rækker i 1. dimension og kolonner i 2. dimension (såvidt jeg husker).
Avatar billede softspot Forsker
20. februar 2012 - 22:49 #3
Hvis din menu ikke er ultra dynamisk (dvs. hvis der er mere end 3-4 brugere der har brug for at få den vist mellem den ændrer sig), kan du med fordel cache den.

Du kan f.eks. gemme den som en færdiggenereret stump html (streng) i Application-objektet.

Alternativt på serverens disk, som en statisk html-fil. Denne kan så includes (også med Server.Execute, hvis du vil), der hvor du har brug for at vise den...

Når menuen så ændrer sig, genererer du den bare til din cache igen og siderne der gør brug af den vil være opdateret med det samme.
Avatar billede c-lund Nybegynder
22. februar 2012 - 07:48 #4
Hej Softspot

I dit første indlæg nævner du noget med at lave et kald til databasen og så bruge rs.GetRows. Har du noget eksempel kode på, hvordan det kunne virke?

Det med en HTML fil med menuen er slet ikke et dumt alternativ.
Avatar billede softspot Forsker
23. februar 2012 - 11:11 #5
Jeg har desværre ikke pt. tid til at sætte mig ned og kode det for dig, men i princippet bør det kunne fungere med udgangspunkt i den eksisterende kode. Dog med den forskel, at du skal slå op i et array, for at finde menupunkterne, samt at du nok skal bruge en støttefunktion til at sortere i arrayet. Dette vil dog givetvis ikke have nogen reel betydning på performance, når alternativet er, at lave opslag i en database... :-)

Hvis du er rigtig skarp sørger du bare for at menupunkterne er sorteret, når databasen afleverer dem, således du blot skal sørge for at aflæse menupunkterne. Du skal blot sørge for at sortere på Ret_Id primært og Ordernummer sekundært:

SQL = "SELECT * FROM Live_Menu_" & MenuNavn & " ORDER BY Ref_Id, Nummer"

så burde menupunkterne ligge i den rækkefølge de skal, når du først, i array'er, har fundet det Ret_id du skal bruge til det aktuelle niveau i menuen...

Mht. cachingmetoden, kan du jo gøre det med udgangspunkt i den nuværende løsning, hvor du f.eks. cacher i Application-objektet når systemet starter og så finde et passende interval hvormed regenereringen skal ske (f.eks. når du ændrer menuen fra dit backendsystem). Du skal dog huske at generereringen skal ske til en streng i stedet for Response, for ellers kan du ikke fange output og gemme det i en cache (hvadenten det er en html-fil eller i application-objektet).
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester