Avatar billede nat Nybegynder
05. april 2005 - 08:42 Der er 41 kommentarer og
2 løsninger

Hjælp til metode

Hej Eksperter

Jeg er gået i stå i en opgave, den er nok let nok:

Jeg har tre klasser: DataHandler (til oprettelse af databasen, og indeholdende main), Ansat (med atributterne aId, aEfterNavn, aFornavn, aDato, aAfdId - svarende til kollonerne i databasen, id, fornavn, efternavn, dato, afdId) og det samme gør sig gældende med Afdeling (afId, afNavn, afBy henholdsvis id, navn, by). Ansat og Afdeling klasserne har "kun" get og set.

Jeg skal nu lave en public metode i min DataHandler klasse der ser således ud:

Ansat GetAnsat(aId)

Hvordan gør jeg det?

Når jeg skal teste det, skal det testes i en consol app. Her er det meningen at når man indtaster den ansattes id, at den pågældende ansatte returneres (fra databasen). Hvordan gør jeg det?
Avatar billede arne_v Ekspert
05. april 2005 - 08:48 #1
du laver en connection
du laver en command med en select
du laver en data reader med ExecuteReader
du laver en Ansat med at agive data fra readeren som argumenter til constructor (eller
med en tom constructor og så sætte properties en af gangen)
du lukker diverse
du returnerer Ansat objektet
Avatar billede burningice Nybegynder
05. april 2005 - 08:50 #2
public void GetAnsat(int aId) {
  OleDbCommand comm = new OleDbCommand("SELECT efternavn, fornavn, dato, afdid FROM tblAnsatte WHERE (id = "+ aId +")", this.conn);
 
  this.conn.Open();
  OleDbDataReader reader = comm.ExecuteReader();

  if (reader.HasRows) {
      Ansat a = new Ansat();

      a.Id = aId;
      a.aEfterNavn = reader.GetString(0);
      a.aFornavn = reader.GetString(1);
      a.aDato = reader.GetDateTime(2);
      a.aAfdId = reader.GetInt32(3);

      reader.Close();
      this.conn.Close();
     
      return a;   
  } else {
      reader.Close();
      this.conn.Close();

      throw new ArgumentException("Ingen ansat med det id");
  }
}
Avatar billede burningice Nybegynder
05. april 2005 - 08:52 #3
bortset fra det første punkt med connection (jeg går ud fra at der er en intern connection i hans DataHandler-klasse man kan bruge), svarer din liste vist 100% overens med min kode - og nej, jeg havde ikke set dit indlæg :P
Avatar billede burningice Nybegynder
05. april 2005 - 08:53 #4
arg... jeg har en fejl

if (reader.HasRows)

skal være

if (reader.Read())
Avatar billede arne_v Ekspert
05. april 2005 - 08:55 #5
http://cert.uni-stuttgart.de/archive/bugtraq/2000/10/msg00330.html

[bemærk at MySQL i 4.1 har strammet op på sikkerheden !]
Avatar billede arne_v Ekspert
05. april 2005 - 09:19 #6
hov forkert tråd - ignorer den
Avatar billede arne_v Ekspert
05. april 2005 - 09:20 #7
Det er nok mest sandsynligt at der er en connection i Datahandler klassen, men
det bør der ikke være.
Avatar billede burningice Nybegynder
05. april 2005 - 09:26 #8
og hvorfor bør der ikke være det? hvis man har lavet en klasse der wrapper omkring de database-specifikke klasser vil det da skabe mindst overhead at have en connection som field, da dette object jo netop vil blive brugt i så og sige alle metoderne i klassen.

Eneste problem man kan løbe ind i er hvis man bruger samme DataHandler-object i flere tråde, men der bør man oprette en ny DataHandler til hver tråd.
Avatar billede md_craig Nybegynder
05. april 2005 - 09:34 #9
en void metode der returnere en ansat? bare mig eller? :P

En helt anden ting... din Ansat klasse skal da vel ikke have et Afdelings ID? det du ender i der er at linke Objekter på ID'er... det går ikke, så den skal vel nærmere tage en Afdeling...

Så:

public class Ansat
{
  private int aID; //Du bør også overveje om denne att er nødvendig...
  private string aEfterNavn;
  private string aFornavn;
  private string aDato;
  private Afdeling aAfd;
...
}

public class Afdeling
{
  private int afId; //Bør igen overveje denne att.
  private string afNavn;
  private string afBy;
...
}

Og så ellers en klasse der holder styr på disse... Singleton fx...
Avatar billede burningice Nybegynder
05. april 2005 - 09:42 #10
:) ja... der var så en fejl mere..

det skal selvfølgelig være

public Ansat GetAnsat(int aId) {

dog kan jeg ikke se hvorfor at et klasse der mapper til en tabel i databasen ikke skal have et id-field. Det vil give en masse problemer hvis den ikke havde, for hvordan ville du da ellers kunne opdatere en ansat f.eks. ?

by the way, så er et field og en attribut ikke det samme. En private variabel der har hele klassen som scope kaldes for et field.
Avatar billede burningice Nybegynder
05. april 2005 - 09:43 #11
og hvorfor vil du have et Singleton pattern i brug? der er forhåbenligt mere end en ansat i firmaet
Avatar billede nat Nybegynder
05. april 2005 - 09:50 #12
>>Cyberfessor
Hvis jeg gør som du skriver, så har jeg ikke mulighed for at få Id, jeg har kun aId, når jeg skal a.Id...

så jeg har metoden:
public Ansat GetAnsat(int aId)

Og her siger jeg efter så: Ansat a = new Ansat(7, "Hansen", "Hannah", system.DateTime.Now, 3);

Og så i min main skriver: console.write("Indtast ansattes id: ");
aid=Console.ReadLine();
data.GetAnsat(7);

Men her kommer den ud og siger at den ansatte ikke findes, hvorfor?
Og hvordan kan jeg undgå at hardkode GetAnsat(7) men rent faktisk hente den ansatte som brugeren taster id'et på?
Avatar billede burningice Nybegynder
05. april 2005 - 09:58 #13
oki... din metode skal så se sådan her ud

public void GetAnsat(int aId) {
  OleDbCommand comm = new OleDbCommand("SELECT efternavn, fornavn, dato, afdid FROM tblAnsatte WHERE (id = "+ aId +")", this.conn);

  this.conn.Open();
  OleDbDataReader reader = comm.ExecuteReader();

  if (reader.HasRows) {
      Ansat a = new Ansat(aId, reader.GetString(0), reader.GetString(1), reader.GetDateTime(2), reader.GetInt32(3));

      reader.Close();
      this.conn.Close();
   
      return a; 
  } else {
      reader.Close();
      this.conn.Close();

      throw new ArgumentException("Ingen ansat med det id");
  }
}

sql-queryen skal du selvfølgelig rettet til så det passer til din database

for at få brugerinput om til et id kan du gøre sådan her:

string aid = Console.ReadLine();
data.GetAnsat(int.Parse(aid));
Avatar billede nat Nybegynder
05. april 2005 - 10:13 #14
>> cyberfessor

ok, men nu når jeg i consolen indtaster et id på en ansat som eksisterer, sker der ikke noget - den skal udskrive den ansattes oplysninger i consolen, hvordan det?
Den breaker fint når jeg indtaster et id, der ikke eksisterer...
Avatar billede arne_v Ekspert
05. april 2005 - 10:40 #15
re 09:26:56)

Fordi .NET har indbygget connection pool. Hele ideen med en sådan er at man kun
låner connection mens man har brug for den.

Hvis man holder på connection, så skalerer ens kode ikke, fordi man kan risikere
at få flere DataHandler instanser end databasen understøtter connections. Og hvis
man skriver sin DataHandler klasse til at håndtere det så har man reelt skrevet sin
egen connection pool oven på .NET connection pool.
Avatar billede nat Nybegynder
05. april 2005 - 11:05 #16
<< cyberfessor

Jeg har godt nok sat den første reader.GetString til reader.GetString(1) - altså starter med 1 og ikke 0, ellers kom der en fejl.
Avatar billede arne_v Ekspert
05. april 2005 - 11:07 #17
det skal være 0 men måske

reader.GetInt(0)

fremfor

reader.GetString(0)
Avatar billede arne_v Ekspert
05. april 2005 - 11:08 #18
I cf's kode er første kollonne efternavn, men hvis du har id først, så ...
Avatar billede nat Nybegynder
05. april 2005 - 11:34 #19
Hmm jeg burde nu have givet den rigtige rækkefølge:

OleDbCommand comm = new OleDbCommand("SELECT id, fornavn, efternavn, dato, afdid FROM tblAnsatte WHERE (id = "+ aId +")", this.conn);

og så har jeg:

Ansat a = new Ansat(aId, reader.GetString(0), reader.GetString(1), reader.GetDateTime(2), reader.GetInt32(3));

Når jeg så i consolen prøver at indtaste et id der eksisterer kommer følgende fejl:

...... The data value could not be converted for reasons other than sign mismatch or dataoverflow....

og den peger så på linien Ansat a = new Ansat.....

skal der noget mere til aId?
Avatar billede arne_v Ekspert
05. april 2005 - 11:54 #20
Du har id som første felt i SELECT listen.

Og forudsat at id er et tal så skal du hente den med GetInt og ikke med GetString.
Avatar billede arne_v Ekspert
05. april 2005 - 11:55 #21
men da du allerede har id så skal GetString(0) nok slet ikke med
Avatar billede nat Nybegynder
05. april 2005 - 12:01 #22
problemt er at hvis jeg gerne ville have aId med (der hvor jeg læser hvad man indtaster) så kan jeg ikke se at aId og id er det samme her, vel?

og hvis jeg skriver Ansat a = new Ansat (aId, reader.GetInt32(0), reader.GetString........ derudaf, hvor reader.GetInt32 refererer til id (og ikke aId), så har jeg for mange argumenter 6 (og der skal kun være 5).
Avatar billede arne_v Ekspert
05. april 2005 - 12:09 #23
WHERE betingelsen sikrer at id og aId er de samme.

Hvis du er meget skeptisk kan du vel:

if(reader.GetInt(0) == aId) {
}

Og du selecter 5 felter. Du skal bruge de 4 sidste. Og de vil have index 1,2,3 og 4
Avatar billede nat Nybegynder
05. april 2005 - 12:28 #24
okay, så kommer jeg til det problem jeg startede ud med..

jeg har:
Ansat a = new Ansat(aId, reader.GetString(1), reader.GetString(2), reader.GetDateTime(3), reader.GetInt32(4));

Når man så taster et aId som eksisterer skriver den ikke den ansattes info ud på skærmen  - hvorfor ikke?
Jeg har gjort som cf sagde: string aid = Console.ReadLine();
data.GetAnsat(int.Parse(aid));
Avatar billede arne_v Ekspert
05. april 2005 - 12:56 #25
Hvordan ser din udskrivning ud ?
Avatar billede nat Nybegynder
05. april 2005 - 13:12 #26
>> arne_v

Undskyld ikke forstået, hvad mener du med min udskrivning?
Avatar billede arne_v Ekspert
05. april 2005 - 13:17 #27
Du siger at den ikke udskriver data til skærmen.

Hvordan ser din Console.WriteLine ud ?

[gerne set i relation til data.GetAnsat(int.Parse(aid))]
Avatar billede nat Nybegynder
05. april 2005 - 13:31 #28
Det eneste jeg har i main er:

Console.WriteLine("Indtast id");
string aid = Console.ReadLine();
data.GetAnsat(int.Parse(aid));

Skal der her være en Console.Write? Hvordan skal den så se ud?
Avatar billede nat Nybegynder
05. april 2005 - 13:32 #29
Forresten, tak for al hjælpen :)
Avatar billede arne_v Ekspert
05. april 2005 - 13:35 #30
Prøv:

Console.WriteLine("Indtast id");
string aid = Console.ReadLine();
Ansat a = data.GetAnsat(int.Parse(aid));
Console.WriteLine(a);
Avatar billede arne_v Ekspert
05. april 2005 - 13:35 #31
Forudsætter at Ansat klassen har en fornuftig ToString metode
Avatar billede nat Nybegynder
05. april 2005 - 13:55 #32
>>arne_v

Det har jeg, og jeps det hjalp :)
Avatar billede nat Nybegynder
05. april 2005 - 13:56 #33
arne_v og cyberfessor smider I ikke lige et svar
Avatar billede arne_v Ekspert
05. april 2005 - 13:59 #34
.
Avatar billede burningice Nybegynder
05. april 2005 - 14:07 #35
svar
Avatar billede md_craig Nybegynder
05. april 2005 - 14:56 #36
svar : 05/04-2005 09:42:12 ; cyberfessor
_____________________________________________________________________________________
Tror der er en masse ting du har misforstået ud fra det jeg skriver...

Normalt vil man ikke rive ID'er med op fra databasen til Objekter (Burde man vide)
Men i nogle tilfælde kan de være nødvendigt... Der vil det dog så være pænere at serialisere sit objekt. tag et kig på fx Object Identifier Patterns...

Men mapning fra Object Orientere til Relationel er et problem som er maget omdiskuteret, og der er utallige måder at løse dette på...

Men nu var det jo afID på Ansat jeg sagde der 100% skulle fjernes, resten af ID'erne sagde jeg så vidt muligt... afID skal helt klart erstattes af private Afdeling afd;

Husk på vi ikke skal linke på ID'er men Referencer...



svar : 05/04-2005 09:43:33 ; cyberfessor
_____________________________________________________________________________________

Singleton patternet vil du kunne tage i brug for at holde styr på dine Ansate, så den ville fx holde en Collection og metoderne AddAnsat og GetAnsat... (Delete og Clear evt)... og samme metoder for Afdelinger om man så vil have en eller flere Singletons eller benytte en anden metode...

Ellers vil dine objecter ligge og flyde og dermed kan du ikke få fat i dem... (Man holder ikke referencer i Presentations lag) (de vil naturligvis kun ligge og flyde til GC komemer forbi)
Avatar billede md_craig Nybegynder
05. april 2005 - 14:57 #37
Og der hvor jeg har lært Programmering blev en Variabel med hele klassen som Scope kaldt en Attribut...
Avatar billede burningice Nybegynder
05. april 2005 - 16:31 #38
det er rigtigt at afdID ikke har nogen steder hjemme, det bør være en reference til en Afdeling-instans.

Dog har jeg lidt svær ved at se din harme over ID i sit object. Alle de OR-mappers jeg kender til er netop afhængige af at den postens primære nøgle i databasen bliver gemt i objectet, da det ellers ikke er muligt at indentificere posten i databasen igen.

Omkring singleton pattern kommer det nok meget an på ens arkitektur i programmet. Det er rigtigt, at hvis man har brug for en unificeret tilgang til sine ansatte og afdelinger er Singleton ikke nogen dum idé. Men det er nu heller ikke nogen ulovlighed at lave en static metode i sin Ansatte-klasse der returnerer en AnsatteCollection, ala det her

public class Ansat {
  public static AnsatCollection GetAll() {
      //Hent alle fra databasen
      //Opret n-ansatte objecter og tilføj til en collection
      //returner collection'en
  }
}

AnsatCollection coll = Ansat.GetAll();

foreach (Ansat a in coll) {
  a.Salary = 100000;
}

På den måde er det også muligt at lave forskellige kriterier for hvilke ansatte man har lyst til at hente ud. Ved et singleton-pattern er man tvunget til at have ALLE ens ansatte liggende i en collection, da man ellers ikke har mulighed for at hente nogle helt specifikke ansatte ud.

Men, ja... guidelines og arkitektur kan man snakke om fra nu af og til dommedag.


Rent teknisk er en attribut i .Net et object man kan sætte som egenskab til klasser og metoder

Eks.

[Developer("cyberfessor", "21")]
public class Me {

  [Obsolete("Don't use Hej; use Bye instead", true)]  <-- dette er en attribut
  public void Hej {
  }
}
Avatar billede md_craig Nybegynder
05. april 2005 - 16:59 #39
Nu var atribut begrebet i forbindelse med alle programmeringssprog...

i .NET ville jeg også nok kalde en Attribut for et Field, og vise den som en Property...

Min Harme over ID hænger sammen med at det hurgtigt leder til at man resikere at benytte ID'er som det der kæder ting sammen... hvilket vil være en fejl...

ID'er er noget vil har i den Relationelle verden mens at vi har referencer i den ObjectOrienterede verden... og at man skal passe på med ikke at kede de 2 vernener for meget sammen, og der er andre måder at løse det på... fx med:

System.Runtime.Serialization


Desuden kan du også sagtens definere i en Singleton af den skal lede i databasen efter en ansat hvis denne ikke findes i din collection, det er et spørgsmål om kode...

Dit tilfælde er et alternativ, men jeg bryder mig mere om at bruge en Singleton som et "Library" frem for at skulle hen og have en mase Statiske samlinger og metoder...
Avatar billede burningice Nybegynder
05. april 2005 - 17:18 #40
Man skal bare passe på med de begreber, da man nemt kan misforstå hinanden når at man ikke bruger samme "regelsæt".

Så du efter dit hoved burde vi skrotte alle databaser og serialisere alle vores objecter  istedet? :) Jeg vil mene man kun bør bruge serialisering når man skal pakke ens object ind for at overføre det, f.eks. over http eller sockets. Man bør ikke bruge Serialisering til at gemme oplysninger for senere at hente det frem igen, med mindre det er noget meget applikationsspecifikt. Baner i et spil f.eks. I et lille program der skal koble sig op mod firmaets oracle-database og hente nogle oplysninger ud hører serialisering jo ingen steder hjemme.
Avatar billede arne_v Ekspert
05. april 2005 - 18:23 #41
jeg er glad for termen "instans variabel"  - de fleste kan regne ud hvad jeg mener
Avatar billede md_craig Nybegynder
05. april 2005 - 22:23 #42
Svar : cyberfessor : 05/04-2005 17:18:09

Jeg ved ikke hvor du har fået ideen om at jeg mener man skulle skrotte databaser???

Det var jo netop til Mapningen fra vores Objekter -> Records -> Objekter...

Men til sidst vil jeg faktisk poientere at du faktisk ikke altid har brug for noget af alt dette... konkret har jeg faktisk i alle de projekter jeg har været med til ikke haft behov for at smide ID på klasser for at smide ID på...

selv om du måske har et hav af klasser i en model er det faktisk nogle gange nok at du har en fast "forbindelse" mellem måske 2 klasser, og disse data er måske enda vigtig information i klassen... typisk har vi haft brug for nogle ID'er externt til systemet som en bruge så kan taste ind... det er oplysninger som:

CPR, Ordrenr, Stregkode, Timestamps+stationsid osv... alle sammen egenskaber og derfor tiladte...

Endnu en muligned er flere PK'er...

Du må også godt definere din PK til at bestå af flere koloner i din db... så længe du opnår en helt unik kombination... kunne være et Telefon nummer kombineret med et navn fx... Et tidspunkt kombineret med en placering...

En hovedregel er bare at et ID i en klasse helst ikke skal være der for ID'ets skyld... der er så måske tilfælde hvor dette ikke er muligt... men derfor sagde jeg også så vidt muligt undgå... frem for at gå ned i en tabel i en database og sige at nå... men Bruger tabel har {id, navn, addresse, telefon} så skal min Bruger klasse sQ også have dette...
Avatar billede md_craig Nybegynder
05. april 2005 - 22:25 #43
en fast "forbindelse" mellem måske 2 klasser --> Refrace...

en fast "forbindelse" mellem klasser og tabeller (records og objekter) i meget få (måske kun 2 fx) af dine klasser
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
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

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