webForumDet fria alternativet

Data från olika tabeller i samma Repeater?

.NET

15 svar · 536 visningar · startad av k0ffe

Medlem sedan maj 2003352 inlägg
Frågan#1

Halloj, jag har lite problem nu när jag vill hämta data från två tabeller och visa i en repeater...

Det är ett forum och jag vill hämta data från tabellen "anvandare", i det här fallet bara användarens bild beroende på anvID:t som finns i forum-tabellen.
Koden jag har för att hämta datan från tabellen forum ligger i forum.vb:

Function forumLista()	
	dim cn as new OdbcConnection("DRIVER={MySQL ODBC 3.51 Driver};SERVER=server;PORT=port;DATABASE=database;UID=uid;PWD=pwd;OPTION=option;")

    Dim da As New OdbcDataAdapter("select * from forum order by senasteSvar desc",cn)
    dim ds as new DataSet
	da.Fill(ds, "forum")
	
  dim objPds as new PagedDataSource()
  objPds.DataSource = ds.Tables("forum").DefaultView
  objPds.AllowPaging = true
  objPds.PageSize = 15
  dim currentPage as integer
  if not Request.QueryString("s") = 0 then
   currentPage=Convert.ToInt32(Request.QueryString("s"))
  else
   currentPage = 1
  end if
  objPds.CurrentPageIndex = currentPage-1
  lblSida.Text = "Sida: " & currentPage.ToString()
  if not objPds.IsFirstPage then
	lnkPrev.NavigateUrl= "default.aspx?s="& Convert.ToString(currentPage-1)						
  end if
  if not objPds.IsLastPage then
	lnkNext.NavigateUrl= "default.aspx?s="& Convert.ToString(currentPage+1)						
  end if

 return objPds
End Function

Och på sidan default.aspx har jag själva repeatern:

<% forum.DataSource = forumLista()
       forum.DataBind()
%>

 <table class="forum" cellpadding="0" cellspacing="0">
 <tr class="head">
<td class="typ">Typ</td>
<td class="rubrik">Rubrik</td>
<td>Senaste inlägg</td>
<td>Svar</td>
<td>Startad av</td>
</tr>
<asp:repeater id=forum runat="server">
	<itemtemplate>
	<tr>
	<td class="typ"><img src="<%# forumTyp(DataBinder.Eval(Container.dataitem, "privat")) %>" alt=""/>
	</td>
	<td class="rubrik"><a href="visa.aspx?FID=<%# databinder.eval(container.dataitem, "FID")%>"><%# databinder.eval(container.dataitem, "rubrik")%></a></td>
	<td><%# databinder.eval(container.dataitem, "senasteSvar")%></td>
	<td><asp:label id="svar" runat="server"/></td>
	<td><%# databinder.eval(container.dataitem, "anvandare")%></td>
	</tr>
</itemtemplate>
</asp:repeater>

Vad jag har förstått så är kanske inte ItemDataBound det bästa att använda rent prestandamässigt om man ska köra en SQL-fråga för varje post?

Tacksam för hjälp...

Medlem sedan maj 20012 812 inlägg
#2

Vad jag har förstått så är kanske inte ItemDataBound det bästa att använda rent prestandamässigt om man ska köra en SQL-fråga för varje post?

ItemDataBound är alltid bäst ur prestanda synpunkt, eftersom du slipper en massa databinder.eval() som inte är så bra u prestanda synpunkt.

Det som inte är så bra är däremot att göra ett nytt SQL anrop för varje post som skall skrivas ut, detta är rent ut sagt korkat, och prestanda dödande. Det du skall göra är att utvidga din första SQL sats så att den även får med information om användaren med ett vanligt INNER JOIN sqlstatement.

Det andra du skall göra är att sluta med användandet av DataSet för sådana här lösningar eftersom DataSet är betydligt mer prestanda krävande än en DataReader.

Det tredje du skall göra är att inte använda dig av PagedSource utan se till så du bara hämtar den datan som du behöver från databasen. Och med tanke på att du använder MySQL som har det trevliga kommandot LIMIT så är den implementationen enkel (MicroSoft när kommer LIMIT till SQL Server?????). Med en SELECT * FORM [Tabel] som du använder så hämtar du ju ALL data som finns i den tabellen, har du då 1 Miljon poster så hämtar du ut alla dem för att kanske visa 10 stycken, det är ju inte så smart.

- M

Medlem sedan maj 2003352 inlägg
#3

Ok, då klarnade det ytterligare, tack!

Gällande PagedSource, så är jag medveten om prestandaförlusten iom min lösning. Men då jag inte har så många poster i den tabellen, och inte kommer ha så många heller så ser jag det inte som ett problem. Än.

Jag har försökt få ihop det med INNER JOIN, men vid DataSet som du skriver om, fastnar jag... Har försökt få datakällan i en DataReader men icke.
Lite hjälp kodmässigt är uppskattat!

Medlem sedan maj 20012 812 inlägg
#4
SqlConnection sqlConnection = new SqlConnection("DIN_CONNECTIONSTRIN");
SqlCommand sqlCommand = new SqlCommand();
SqlDataReader sqlDataReader = null;

sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = "SELECT.....";
sqlCommand.Connection = sqlConnection;

sqlConnection.Open();
sqlDataReader = sqlCommand.ExecuteReaderCommandBehavior.Close);

//-- Do what you want with your datareader
//-- But dont forgett to do sqlDataReader.Close() when
//-- your done with it, so you release connections to your databas

Skrivet helt ur huvudet så små fel har säkert smugit sig in.

- M

Medlem sedan maj 2003352 inlägg
#5

Ok, tack. Men tyvärr löser det inte mitt problem.
Man kan inte, vad jag förstår, använda DataReader med PagedDataSource, det går inte att använda DataBind() och utan det får man ett felmeddelande gällande ICollection el liknande.
Jag läste en annan tråd där problemet var just att använda DataReader ihop med PagedDataSource, detta löstes precis så som min variant är, dvs med DataSet.

Jag vill ju bara kunna visa användarens bild, ska det vara så svårt att lösa... damnit :)

Uppskattar all hjälp jag kan få!

Medlem sedan maj 20012 812 inlägg
#6

Man kan inte, vad jag förstår, använda DataReader med PagedDataSource

Hmm visste jag inte, men vid närmare eftertanke så är det en logisk slutledning eftersom en DataReader är en read-forward only cursor. Medans din PagedDataSource säkert kräver möjlighet att hoppa tillbaka bland posterna också.

alternativiet till datareader är så fall en DataTable som är lite lättare än ett DataSet, men det du verkar ha problem med är din SQL sats där du inte kan få till din INNER JOIN statement. Hör efter i SQL forumet för hjälp med din SQL sats.

- M

Medlem sedan maj 2003352 inlägg
#7

Löste det...
Dock utan att använda DataTable, men om det för övrigt inte är en bra lösning så hojta gärna:

Function forumLista()	
	dim cn as new OdbcConnection(blabla)

    Dim da As New OdbcDataAdapter("SELECT forum.*, anvandare.bild, count(*) as antalsvar FROM forum INNER JOIN forum_svar ON forum.FID=forum_svar.SID INNER JOIN anvandare ON forum.anvID=anvandare.ID GROUP BY forum.FID ORDER BY forum.senasteSvar desc",cn)
    dim ds as new DataSet
	da.Fill(ds, "forumet")
	
  dim objPds as new PagedDataSource()
  objPds.DataSource = ds.Tables("forumet").DefaultView
  objPds.AllowPaging = true
  objPds.PageSize = 15
  dim currentPage as integer
  if not Request.QueryString("s") = 0 then
   currentPage=Convert.ToInt32(Request.QueryString("s"))
  else
   currentPage = 1
  end if
  objPds.CurrentPageIndex = currentPage-1
  lblSida.Text = "Sida: " & currentPage.ToString()
  if not objPds.IsFirstPage then
	lnkPrev.NavigateUrl= "?visa=forum&s="& Convert.ToString(currentPage-1)						
  end if
  if not objPds.IsLastPage then
	lnkNext.NavigateUrl= "?visa=forum&s="& Convert.ToString(currentPage+1)						
  end if

 return objPds
End Function
Medlem sedan maj 2003352 inlägg
#8

Det tredje du skall göra är att inte använda dig av PagedSource utan se till så du bara hämtar den datan som du behöver från databasen. Och med tanke på att du använder MySQL som har det trevliga kommandot LIMIT så är den implementationen enkel (MicroSoft när kommer LIMIT till SQL Server?????). Med en SELECT * FORM [Tabel] som du använder så hämtar du ju ALL data som finns i den tabellen, har du då 1 Miljon poster så hämtar du ut alla dem för att kanske visa 10 stycken, det är ju inte så smart.

Nu har jag stött på en liknande variant men där posterna är närmare 400 istället för c:a 40. Om jag nu vill använda LIMIT, hur ska jag då gå tillväga? Ska jag helt enkelt ha olika SQL-frågor beroende på vilket sidnummer det är? Förstod dig inte riktigt där Gladh...

Medlem sedan maj 2003352 inlägg
#9

Ingen som kan hjälpa mig lite? Eller är prestandaskillnaden såpass liten när det gäller "endast" 400 poster att man inte märker skillnaden?

Medlem sedan maj 20012 812 inlägg
#10

400 eller 40 poster spelar inte så stor roll, det börjar nog märkas mer när det rör sig om tusentals poster.

Hur just LIMIT fungerar vet jag inte så bra eftersom jag inte arbetar mot MySQL, men OM det fungerar så här:

SELECT * FROM [Tabel] LIMIT 1, 10

Så säger den att ta första posten (1) och hämta 10 poster (10). Det betyder att du när du vill visa post 11-20 skall skriva

SELECT * FROM [Tabel] LIMIT 11, 10

och post 21-30

SELECT * FROM [Tabel] LIMIT 21, 10

Det betyder att du för varje sida som du vill visa måste ändra just startnummret, och det kommer att ge dig olika SQLsatser varje gång, men startsiffran kan du ju räkna ut så SQL satsen blir.

startPos = (currentPage * 10) + 1;
sql = "SELECT * FROM [Tabel] LIMIT "+ startPos + ", 10";

där currentPage är den sida som du vill visa.

- M

Medlem sedan maj 2003352 inlägg
#11

Ok, tack för svaret... Men om jag väljer endast de poster jag vill visa/sida så fungerar ju inte pagingen. Den räknar ju mellan alla poster, om jag då inte har alla med så finns det ju inga fler att bläddra mellan...

Medlem sedan maj 20012 812 inlägg
#12

Nope den inbyggda pagingen fungerar inte eftersom den kräver att du hämtar ALL data från databasen.

Om du vill använda dig av Limit så får du själv hantera pagingen, genom att kontrollera hur många poster det finns totalt av din sökning och sedan själv bygga en pagingfunktion som visar nästa sida osv osv...

Helt klart mer jobb för dig, och om det endast rör sig om 400 poster och det inte är allt för mycket data i dem så är det kanske inte lönt att lägga ner den tiden, men om det rör sig om tusentalsposter och det är mycket data i varje post så är det helt klart en prestandavinst att göra det.

- M

Medlem sedan maj 2003352 inlägg
#13

Ok, tack för all hjälp Gladh! Det är uppskattat!

Medlem sedan maj 2003352 inlägg
#14

Hmm... nu har jag gjort såhär:

Function forumSvar()

 dim startPos as Integer
 dim currentPage as Integer
 dim Page as String
 Page = Request.QueryString("sidNr")
 IF len(Page) = 0 OR Page = 1 THEN
   currentPage = 0
   Page = 1	
 ELSE  
   currentPage = Page-1 
 END IF
 startPos = currentPage*10
 lblForumInlaggSida.Text = "Sida: " & Page
 IF NOT (Page = 1 OR len(Page) = 0) THEN
  lnkForumInlaggPrev.NavigateUrl="?sida=visaInlagg&FID=" & Request.QueryString("FID") & "&sidNr=" & currentPage	
 END IF
 lnkForumInlaggNext.NavigateUrl="?sida=visaInlagg&FID=" & Request.QueryString("FID") & "&sidNr=" & Page+1
 dim cn as new OdbcConnection("DRIVER={MySQL ODBC 3.51 Driver};SERVER=;PORT=;DATABASE=;UID=;PWD=;OPTION=3;")
 Dim Cmd as new OdbcCommand("SELECT forum_svar.*, anvandare.bild FROM forum_svar INNER JOIN anvandare ON forum_svar.anvID=anvandare.ID WHERE SID=" & Request.QueryString("FID") & " ORDER BY forum_svar.datum LIMIT " & startPos & ", 10",cn)
 cn.Open()
 return Cmd.ExecuteReader(CommandBehavior.CloseConnection)
End Function

Men jag vill ju också räkna hur många sidor det är så man inte kan bläddra all världens väg framåt... Frågan är alltså, hur gör jag det? :)

Medlem sedan juli 2004206 inlägg
#15

Du kan ju köra en count och returnera det samtidigt som ditt andra svar.

Ett litet tips kan också vara att alltid plocka 1 rad för mycket för varje sida. På så sätt så vet du om det finns fler sidor och därav också om du ska rita ut en "next page" knapp... (exempelvis hämta 11 resultat. Får du 11 resultat så vet du att du ska visa 10 resultat + en "next" knapp.. =)

Medlem sedan maj 2003352 inlägg
#16

Ett litet tips kan också vara att alltid plocka 1 rad för mycket för varje sida. På så sätt så vet du om det finns fler sidor och därav också om du ska rita ut en "next page" knapp... (exempelvis hämta 11 resultat. Får du 11 resultat så vet du att du ska visa 10 resultat + en "next" knapp.. =)

Smart, men jag kommer bara inte på hur jag ska göra rent kodmässigt! Vilket som är bäst...

263 ms totalt · 4 externa anrop · v20260731065814-full.1dc6f849
119 ms — deklarationer (db)
0 ms — hämta statistik (cache)
138 ms — hämta tråd, inlägg och bilagor (db)
122 ms — ändringar (db)