webForumDet fria alternativet

En-till-många relation

11 svar · 538 visningar · startad av K-man

K-manMedlem sedan nov. 200217 inlägg
#1

Hej!

Jag har 2 tabeller - Order och OrderLines med en 1-to-many relation. När jag skapar ett Order objekt vill jag kunna lista ut flera Orderlines som hör till en order. Hur skriver jag detta?

Order
-------
private Date createDate;
private Date deliveryDate;
private int price;
private int freightCost;
private int status;
private int paymentMode;
private int totalVolume;
private int totalWeight;
private int totalCost;
private int versionNo;

OrderLines
--------------
private String articleNo;
private String articleName;
private int quantity;
private int price;
private int volume;
private int weight;
private int deliveryDate;

MVH Johan

LimeMedlem sedan sep. 2001961 inlägg
#2

Förtydliga. Är detta en databasmodell, en objektmodell eller??

Vad menar du med tabell?

Nomalt är modellerar man så att Order innhåller ett attribut orderLines som är lämplig Collection (t.ex HashMap) och så har man metoderna addOrderLine(OrderLine ol), removeOrderLine(OrderLine ol) och kanske listAllOrderLines()...

När man sedan skapar en Order så kan man antingen välja att skicka men en Collection i konstruktorn.

/

K-manMedlem sedan nov. 200217 inlägg
#3

Det e en objekt modell.

Har du någon bra exempelkod jag kan kolla på?

erkaMedlem sedan dec. 19996 522 inlägg
#4

Vad menar du när du skriver

jag skapar ett Order objekt vill jag kunna lista ut flera Orderlines som hör till en order.

erkaMedlem sedan dec. 19996 522 inlägg
#5

Jag har fått lära mig att i ditt fall göra en referens från orderItem till Order, sen skapar du i order en collection orderItems, kanske i en arraylist , i din collection lägger du de orderItemobjekt du vill ska höra till ordern.

typ

import java.util.*;

public class Order 
{
  //Alla dina instansvariablar
  private ArrayList orderItems;

  public Order()
  {
    //Gör vad du vill här
    setOrderItems(new ArrayList());
  }
  
  //alla dina andra instansmetoder
  
  private void setOrderItems(ArrayList a){
    orderItems = a;
  }
  
  private ArrayList getOrderItems(){
    return orderItems;
  }
  
  public void addOrderItem(orderItem o){
    getOrderItems().add(o);
  }
  
  public void removeOrderItem(orderItem o){
    getOrderItems().remove(o);
  }
  
}

I Orderitem lägger du sedan koppling till ett Orderobjekt, null förslagsvis i din konstruktur, men du skapar instansmetoder för denna.

RED/ Såg nu att det var OrderLines och inte OrderItem, men du förstår nog ändå :)

K-manMedlem sedan nov. 200217 inlägg
#6

public void addOrderItem(orderItem o){
getOrderItems().add(o);
}

public void removeOrderItem(orderItem o){
getOrderItems().remove(o);
}

Känns konstigt att du har orderItem o som inparameter, borde det inte vara ArrayList orderItem ?

erkaMedlem sedan dec. 19996 522 inlägg
#7

Nej varför då, du ska jag i din Order klass hålla någon form av collection innehållandes just orderItemsobjekt, eller som vi nu kan säga när jag sett att jag läste fel orderLinesobjekt.

Metoden getOrderItems() returnrerar en ArrayList, och med ArrayLists metod add (som tar in ett objekt bland annat) lägger jag således in det objektet jag skickar in.

K-manMedlem sedan nov. 200217 inlägg
#8

Okey, jag fattar du...du hade skrivit inparameterns typ (orderItem) med liten bokstav, men det är ju en klass så den ska vara med stor bokstav. Det var det som förvirrade mig.

public void addOrderItem(orderItem o){
getOrderItems().add(o);
}

Dock fattar jag nog inte riktigt hur det hela ska fungera. Kolla här på min kod.

Order
-------

public class Order
{
//Alla dina instansvariablar
private String countryCode;
private String customerOrderNo;
private String customerNo;
private Date deliveryDate;
private int price;
private List orderItems;

public void print(){
for(Iterator i=orderItems.iterator(); i.hasNext(); ) {
Object[] obj = (Object[]) i.next();
String countryCode = (String) obj[0];
String customerOrderNo = (String) obj[1];
String orderLineNo = (String) obj[2];
String articleNo = (String) obj[3];
String articleName = (String) obj[4];
String quantity = (String) obj[5];
String price = (String) obj[6];
String volume = (String) obj[7];
String deliveryDate = (String) obj[8];

	System.out.println("CountryCode: " + countryCode);
	System.out.println("customerOrderNo: " + customerOrderNo);
	System.out.println("orderLineNo: " + orderLineNo);
	System.out.println("articleNo: " + articleNo);
	System.out.println("articleName: " + articleName);
	System.out.println("quantity: " + quantity);
	System.out.println("price: " + price);
	System.out.println("volume: " + volume);
	System.out.println("deliveryDate: " + deliveryDate + "\\n");
	
}

}

public Order()
{
//Gör vad du vill här
setOrderItems(new ArrayList());
}

//alla dina andra instansmetoder

private void setOrderItems(List a){
orderItems = a;
}

private List getOrderItems(){
return orderItems;
}

public void addOrderItem(OrderItem o){
getOrderItems().add(o);
}

public void removeOrderItem(OrderItem o){
getOrderItems().remove(o);
}

//...getter & setter för attributen

}

OrderItem
-------------

import java.util.*;

public class OrderItem {
//Alla dina instansvariablar
private String countryCode;
private String customerOrderNo;
private String orderLineNo;
private String articleNo;
private String articleName;
private int quantity;
private int price;
private int volume;
private int weight;
private Date deliveryDate;
private Order order;

public OrderItem() {
//Gör vad du vill här
//setOrderItems(new ArrayList());
setOrder(new Order());
setCountryCode("SE");
setCustomerOrderNo("135020");
setOrderLineNo("1");
setArticleNo("1111");
setArticleName("BILLY HYLLA");
setQuantity(10);
setPrice(1500);
setVolume(150);
setWeight(20);

}

//alla dina andra instansmetoder

// setter metoder för övriga attribut

/\*\*
 \* @param order
 \*/
public void setOrder(Order order) {
	this.order = order;
}

/\*\*
 \* @param string
 \*/
public void setOrderLineNo(String string) {
	orderLineNo = string;
}

// setter metoder för övriga attribut

}

OrderMain
-------------

public class OrderMain {
public static void main(String[] args) throws Exception{
OrderItem newOrderItem = new OrderItem();
Order newOrder = new Order();

	newOrder.addOrderItem(newOrderItem);

	newOrder.print();
}

}

Jag kör detta med får följande fel:

java.lang.ClassCastException: OrderItem
at Order.print(Order.java:15)
at OrderMain.main(OrderMain.java:11)
Exception in thread "main"

Har jag tänkt fel eller?

K-manMedlem sedan nov. 200217 inlägg
#9

Jag kan se att den lägger in i listan men hur listar man ut den. Jag får inte rätt på Iteratorn..

LimeMedlem sedan sep. 2001961 inlägg
#10

När du gör add(OrderItem o) är det inte nödvändigt att använda getOrderItems(). Du vet själv vad du sparar dina OrderItems i internt.

getOrderItems() bör framför allt användas av andra klasser som behöver ha alla OrderItems som tillhör en viss Order.

Orsaken till att man döljer implementationen på detta sätt är för att ha möjlighet att alltid returnera samma typ (t.ex en ArrayList) oavsett hur det är lagrat internt.

En annan sak som är bra att göra är att inte returnera referensen till den interna lagringen utan till en klon. Så som det är inmplementerat här kan en anropande klass få access direkt till attributet "orderItems" och manipulera på detta. Det gör att man lika gärna kunde exponera "orderItems" direkt som publikt attribut.

För att svara på din sista fråga:

for(Iterator i=orderItems.iterator(); i.hasNext(); ) {
Object[] obj = (Object[]) i.next();

Det här är fel. Du försökar class-casta en OrderItem till en Object-array...

När man skapar en iterator får man nästa objekt i listan, inte en lista. Verkar lite bakvänt att man returnerar en lista från en lista. Då hade man lika gärna kunnat accessa listan direkt.

Det ska nog se ut såhär:

for(Iterator i=orderItems.iterator(); i.hasNext(); ) {
OrderItem orderItem = (OrderItem) i.next(); 
String countryCode = orderItem.getCountryCode();
... osv.

Fast jag skulle göra en "toString()"-överlagring i orderItem som skriver ut alla attribut i klassen.

/Lime

K-manMedlem sedan nov. 200217 inlägg
#11

Kanon att det funkar nu. Man tackar.

Men när du säger...

När du gör add(OrderItem o) är det inte nödvändigt att använda getOrderItems(). Du vet själv vad du sparar dina OrderItems i internt.

...menar du då att det räcker med att använda sitt attribut orderItem istället för getOrderItems()?

Du skriver oxå

En annan sak som är bra att göra är att inte returnera referensen till den interna lagringen utan till en klon. Så som det är inmplementerat här kan en anropande klass få access direkt till attributet "orderItems" och manipulera på detta. Det gör att man lika gärna kunde exponera "orderItems" direkt som publikt attribut.

Jag har orderItem som private och även get och set metoder för OrderItem. Menar du att även add och remove metoderna borde vara privata? Eller hur kan andra klasser få access till den?

Hur skulle man i denna lösning få det säkrare?

LimeMedlem sedan sep. 2001961 inlägg
#12

Nu kommer en sen och lite filosofisk utläggning. Känsliga läsare varnas... ;-)

I din klass Order har du ett attibut OrderItems som är en List (som för övrigt inte är en optimal typ att använda). Den är privat och är bara accessbar innifrån klassen.

Hade den varit protected hade den varit accessbar från klassen själv OCH alla klasser som ärver från klassen. Om den är public kan alla accesa och manipulera attributet.

get/set-metoder brukar kallas för manipulatorer. Det är här det blir filosofiskt. Vissa anser att det inte är någon mening med att ha getter/setter-metoder för enkla attribut som String, int, boolean o.s.v eftersom de ändå i princip exponeras publict genom getter/setter-metoderna. Det tycker inte jag.

Anyway... När man börjar prata om andra saker som t.ex att kunna lägga till en OrderItem så blir det lite annorlunda.

Du vet hur du lagrar OrderItems internt. Om det är i en lista, en HashMap, en Vector eller direkt i en databas. För den som vill lägga till en OrderItem är det fullständigt onödig information. Denna vill använda addOrderItem(OrderItem o) oavsett hur du väljer att lagra detta OrderItem.

Anta att man bygger ut systemet och får flera subtyper av OrderItem (kommer inte på något bra exempel just nu) och dessa olika typer lagras i olika attribut. Det behöver inte den som lägger till en OrderItem veta utan bara att denna ska använda addOrderItem.

Samma sak med removeOrderItem.

För getAllOrderItems() gäller samma sak MEN du behöver inte använda den publica accessorn för att accessa ditt eget attribut.

Vad man bör göra i en getAllOrderItems()-metod är att inte skicka tillbaka attributet som det är utan en kopia av listan. Om man som du gör skickar tillbaka själva attributet kan den som tar emot det manipulera det som finns i attributet direkt utan att klassen Order har kontroll över vad som görs och hur. Inte bra. Istället bör den returnera en kopia (clone) på listan... eller kanske inte ens en lista.

För att exemplifiera lite vad jag menar. Jag skulle välja att använda en HashMap för att enklare kunna slå upp vilken OrderItem som ska tas bort eller manipuleras.

getAllOrderItems däremot kan mycket väl returnera en List av något slag. Det döljer implementationen och gör att du enklare kan ändra attributet utan att behöva ändra på get/set och getAll-metoderna.

Svammelsvar mitt i natten men jag hoppas du blev lite klokare.

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