webForumDet fria alternativet

Returnera resultset

10 svar · 976 visningar · startad av larsp

larspMedlem sedan feb. 20045 inlägg
#1

Hej! Jag går på högskola och ska göra ett databas program för java. Ska ha databashanteraren och grafiska gränssnittet separerat. Tänkte då att jag skulle returnera ett resultset från en metod i databashanterar-klassen, och sedan anropa detta objekt i grafiska gränssnittet.

Men har nu läst att detta inte går. Någon som har förslag hur man kan göra?

Mc FettoMedlem sedan nov. 20022 355 inlägg
#2

Det går, men man får ju ifrån det grafiska gränssnittet deklarerea en resultSet.
t ex:
resultSet = myDb.getResultset()

larspMedlem sedan feb. 20045 inlägg
#3

Men fungerar det? Har provat följande:

I min databashanterare:

/* metod som hämtar ut allt från tabellen Exempel*/
public ResultSet selectAllFromExempel()
{
int kolumnTal;
String kolumnText;
String kolumnPM;
Date kolumnDatum_tid;
boolean kolumnJa_nej;

	try
	{
		/\*Ställer en fråga till databasen\*/
		rs = stmt.executeQuery("select \* from student");
		int rad = 0;
		
		/\*Stegar igenom svaren i ResultSet-objektet\*/
		while(rs.next())
		{
			rad++;
			
			/\*Plocka ut information från rs-variabeln. Använd en metod som motsvarar den datatyp
			du vill plocka ut ur databasen. Som parameter anger man kolumnnamnet inom "fnuttar".\*/
			kolumnTal = rs.getInt("Sid");
			kolumnText = rs.getString("Namn");
			
			
			/\*Skriver ut den information man fick ut från databasen\*/
			System.out.println("\*\*\*\*\*\*\*\*\* RAD " + rad + "\*\*\*\*\*\*\*\*\*");
			System.out.println("Sid: "+ kolumnTal);
			System.out.println("Namn: " + kolumnText);
			
		}
		/\*Stänger ResultSet-objektet\*/
		//rs.close();
		
	}
	catch(SQLException sqle)
	{
		sqle.printStackTrace();
	}
	
	return rs;
}

I mitt grafiska gränssnitt:
Databashanterare dbh= new Databashanterare(); //from ConnectionJDBC
//Connection dbConnect = null;
Statement dbStatement = null;
ResultSet dbRS = null;
try {
dbRS = dbh.selectAllFromExempel();
presentResultSet(dbRS);
} catch (SQLException sqlex) {
JOptionPane.showMessageDialog(null,sqlex.getMessage());
}
finally {
dbh.avslutaKoppling();
}
}

ResultSet dbRS = null;

Mc FettoMedlem sedan nov. 20022 355 inlägg
#4

Jo, du loopar ju igenom resultSet i databashanteraren tills den står på NULL. Returnera istället resultset innan du loopar och gör loopen i det grafiska gränssnittet!

sgtpepperMedlem sedan apr. 20007 588 inlägg
#5

Returnera inte ett resultSet, det är inte snyggt. Bättre är att skapa en dataklass som håller en rad med information ur databasen och som du sedan lägger in i ett collection-objekt som du returnerar ut, t.ex:

public class Student {
  private int kolumnTal;
  private String kolumnText = null;

  public void setKolumnTal(int kolumnTal) {
    this.kolumnTal = kolumnTal;
  }

  public void setKolumnText(String kolumnText) {
    this.kolumnText = kolumnText;
  }

  public int getKolumnTal() { return kolumnTal; }
  
  public String getKolumnText() { return kolumnText; }
}

I din rs-loop:


ArrayList results = new ArrayList();
while(rs.next()) {
  kolumnTal = rs.getInt("Sid");
  kolumnText = rs.getString("Namn");
  
  Student student = new Student();  
  student.setKolumnTal(kolumnTal);
  student.setKolumnText(kolumnText);
  
  // lägg in aktuell rad i resultat-listan
  results.add(student);  

  rs.close();
}

I ditt grafiska gränssnitt så kan du då plocka ut en Iterator från resultatlistan och iterera igenom:

  Collection results = dbh.selectAllFromExempel();
  Iterator i = results.iterator();
  while(i.hasNext()) {
    Student student = (Student)i.next();

    // gör bra grejor med studentobjektet
    System.out.println(student.getKolumnText());
  }

Fältnamn som kolumnText/kolumnTal känns för övrigt lite bökiga, fimpa "kolumn"-prefixet.

larspMedlem sedan feb. 20045 inlägg
#6

Menar du att man ska ha en klass till varje tabell?

sgtpepperMedlem sedan apr. 20007 588 inlägg
#7

larsp skrev:

Menar du att man ska ha en klass till varje tabell?

Nej, inte nödvändigtvis, men du skall inte exponera ut resultset-objekt ut i presentationsskiktet. Det ger inte en skiktad lösning och är allmänt bökigt med tanke på att du inte kan stänga din databaskoppling innan du läst resultset:et, detta innebär att du måste hålla kopplingen öppen tills dess att resultset:et visats i presentationsskiktet. Om du istället fyller dataobjekt med datat och returnerar så kan du stänga kopplingen direkt.

Beroende på din datamodell så kanske du behöver en eller flera dataklasser som innehåller poster från din databas, det kan data som samlats ihop från en eller flera tabeller.

larspMedlem sedan feb. 20045 inlägg
#8

Tack, ni har varit till mycket hjälp. Återkommer om jag har fler frågor.

Mc FettoMedlem sedan nov. 20022 355 inlägg
#9

sgtpepper skrev:

larsp skrev:

Menar du att man ska ha en klass till varje tabell?

Nej, inte nödvändigtvis, men du skall inte exponera ut resultset-objekt ut i presentationsskiktet. Det ger inte en skiktad lösning och är allmänt bökigt med tanke på att du inte kan stänga din databaskoppling innan du läst resultset:et, detta innebär att du måste hålla kopplingen öppen tills dess att resultset:et visats i presentationsskiktet. Om du istället fyller dataobjekt med datat och returnerar så kan du stänga kopplingen direkt.

Beroende på din datamodell så kanske du behöver en eller flera dataklasser som innehåller poster från din databas, det kan data som samlats ihop från en eller flera tabeller.

Kan man inte på något sätt skicka in en klass till sin databashanterare som i sin tur "går" igenom attributen i klassen och utifrån dessa skapa en selectsat (t ex), denna resultset lägger man sedan i någon collection och returnerar!? Vore ju bra om man skulle kunna skapa något relativt generel databashanterare!

NickemannenMedlem sedan aug. 20003 575 inlägg
#10

Jag gjorde något liknande men det kanske inte var det bästa sättet.

OBS!
Var min första i java och jag skrev den rätt snabbt
getConnection() är en statisk metod där jag skapar min databaskoppling.
strFields innehåller vilka attributnamn jag vill få ut och i vilken ordning. Sedan retuneras detta i den ordningen man skrev dom.
t.ex. den kan se ut såhär

{"t_id","t_datum","rapport"}

Allt retuneras i en String[][]

första är för vilken rad. den andra är för om vi t.ex. vill få ut datum på rad 5 så ser det ut såhär.

String[4][1] (String är bara ett namn).

static public String[][] getData(String strSql, String[] strFields)
	{
		
		Connection objConn = getConnection();
		if(objConn != null)
		{		
			try
			{
				
				Statement objStmt = objConn.createStatement();
				ResultSet objRs = objStmt.executeQuery(strSql);
		
				int intIndex = 0;
				while(objRs.next())
				{
					intIndex++;
				}
				objRs.close();
			
				if(intIndex == 0)
				{
					return new String[0][0];
				}
				
				objRs = objStmt.executeQuery(strSql);
			
				String[][] strData = new String[intIndex][strFields.length];
				
				int intIndex2 = 0;
				while(objRs.next())
				{
					for(int i=0;i < strFields.length;i++)
					{
						strData[intIndex2][i] = objRs.getString(strFields[i]);
					}
					intIndex2++;
				}
				objConn.close();
				return strData;
			
			}
			catch(SQLException SE)
			{
				System.out.println(SE.getMessage()+SE.getSQLState());
			}
	}
		return new String[][] {};
	}

Det finns 2 stora problem med denna bara.

Eftersom jag inte visste hur många rader jag skulle få som svar var jag först tvungen att köra en genomgång för att få reda på det vilket leder till en massa extra krävande kod måste köras.

Samt att den inte kastar några felmeddelanden.

LimeMedlem sedan sep. 2001961 inlägg
#11

Njea...

Jag skulle göra så att jag lägger allt i en annan typ av lista först, t.ex. en Vector och sedan använda Collections.toArray().

Det måste finnas någon bättre datatyp än en två-D-String-array som du kan returnera...

143 ms totalt · 3 externa anrop · v20260731065814-full.0e50b1ef
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
141 ms — hämta tråd, inlägg och bilagor (db)