# Hibernate | Annotationsproblem



## Dit_ (6. Apr 2011)

Hallo zusammen ich habe in meinem HibernateTestprojekt 3 Klassen.


```
@Entity
@Table(name = "INCIDENT")
public class DBIncident implements Serializable {
	
	private static final long	serialVersionUID	= -4424760023780990894L;
	
	@Id
	@GeneratedValue
	@Column(name = "ID")
	private Long				id;
																				
	@Column(name = "DESCRIPTION", columnDefinition = "LONGTEXT")
	private String				description;
	
	@OneToOne(cascade = CascadeType.ALL, optional = false)
	private DBRoad				road;
	
	@Column(name = "DURATION_FROM")
	private Date				dateFrom;
	
	@Column(name = "DURATION_TILL")
	private Date				dateTill;

	@OneToOne(cascade = CascadeType.ALL, optional = false)
	private DBLocation			mainLocation;

	@OneToOne(cascade = CascadeType.ALL, optional = false)
	private DBLocation			locationFrom;

	@OneToOne(cascade = CascadeType.ALL, optional = false)
	private DBLocation			locationTo;
	
	@Column(name = "LENGTH")
	private Double	length;
	
	@Column(name = "STATUS_ACTIVE")
	private Boolean				status;

//getter/setter...
	
}
```



```
@Entity
@Table(name = "LOCATION")
public class DBLocation implements Serializable{
	
	private static final long	serialVersionUID	= -4204049626973488449L;

	@Id
	@GeneratedValue
	@Column(name = "ID")
	private Long	id;
	
	@Column(name = "DESCRIPTION")
	private String	description;
	
	@Column(name = "LATITUDE")
	private Double	latitude;
	
	@Column(name = "LONGITUDE")
	private Double	longitude;
}
```



```
@Entity
@Table(name = "ROAD_TYPE")
public class DBRoad implements Serializable {
	
	private static final long	serialVersionUID	= 3438959442923344472L;
	
	@Id
	@GeneratedValue
	@Column(name = "ID")
	private Long				id;
	
	@Column(name = "TYPE")
	private String				type;
	
	@Column(name = "NR")
	private Long				number;
}
```
Es muss folgendes passieren:

Ich habe (erstmal) 3 Verschiedene RoadTypen, d.h die Tabelle *ROAD_TYPE* soll 3 Einträge haben.

Wenn ich ein Objekt *DBIncident * in die DB speichere so soll fuer DBRoad nur die ID aus der Tabelle ROAD_TYPE genommen werden. Stattdessen werden bei mir jedesmal neue Einträge in die Tabelle ROAD_TYPE geschrieben... wie schaffe ich dass die ID automatisch aus der Tabelle ROAD_TYPY genommen wird.?

Ich habe versucht die Hibernate Dokumentation zu lesen, aber die ist ja eine null-lösung für Anfänger...

danke schon mal!


----------



## mvitz (6. Apr 2011)

Lösung 1:

Du speicherst dir die 3 RoadType Objekte und setzt dann auch nur diese (nachdem du die aus der DB geholt hast).

Lösung 2:
Wäre es für RoadType evtl. sinnvoller ein enum zu nutzen? Dann würde ich das auch machen.


----------



## Dit_ (6. Apr 2011)

ok RoadTyp wird in Anwendung tatsächlich als enum verwendet ich dachte ich verpacke mal das ganz in eigene DBObjekte ...

ok wie mache ich das dann mir enums?

danke


----------



## mvitz (6. Apr 2011)

```
@Entity
public class Incident {

    @Id
    @GeneratedValue
    private Long id;

    @Enumerated(EnumType.STRING)
    private Road road;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Road getRoad() {
        return road;
    }

    public void setRoad(Road road) {
        this.road = road;
    }

}
```


```
public enum Road {

    HIGHWAY, STREET;

}
```

Dann wird das enum allerdings nicht in einer extra Tabelle gespeichert, sondern direkt in der Incident Tabelle.


----------



## Dit_ (6. Apr 2011)

ach ich nee, mein Fehler.... Ausser RoadType habe ich doch noch Road Nummer in der Klasse DBRoad, ich muss also Speichern können: AUTOBAHN, 5 ,Sprich A5 in Deutschland  :/


----------



## mvitz (6. Apr 2011)

D.h. ein "richtiges" Enum ist hier dann doch eher unbrauchbar, da bei einer neuen Autobahn vermutlich nicht das Programm geändert werden soll, sondern lediglich ein neuer Datensatz angelegt werden soll?

Möchtest du denn auch über eine bestimmte Road auf alle dort passierten Incidents zurückgreifen können?


----------



## Dit_ (6. Apr 2011)

mvitz hat gesagt.:


> D.h. ein "richtiges" Enum ist hier dann doch eher unbrauchbar, da bei einer neuen Autobahn vermutlich nicht das Programm geändert werden soll, sondern lediglich ein neuer Datensatz angelegt werden soll?
> 
> Möchtest du denn auch über eine bestimmte Road auf alle dort passierten Incidents zurückgreifen können?



Eigentlich nicht, (man könnte aber später extra view dafür machen oder?), ist aber zur Zeit nicht wichtig.


----------



## mvitz (6. Apr 2011)

Dann ginge doch z.B. folgendes:


```
@Entity
public class Incident {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    private Road road;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Road getRoad() {
        return road;
    }

    public void setRoad(Road road) {
        this.road = road;
    }

}
```


```
@Entity
public class Road {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private Integer number;

    /** only for persistence provider! */
    Road() {
    }

    public Road(String name, Integer number) {
        this.name = name;
        this.number = number;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Integer getNumber() {
        return number;
    }

}
```


```
public class Main {

    public static void main(String[] args) {
        EntityManager em = Persistence.createEntityManagerFactory("enum").createEntityManager();
        
        em.getTransaction().begin();
        em.persist(new Road("A", 1));
        em.persist(new Road("A", 2));
        em.flush();
        em.getTransaction().commit();
        
        em.clear();
        
        Incident i = new Incident();
        i.setRoad(findRoad("A", 1, em));
        
        em.getTransaction().begin();
        em.persist(i);
        em.flush();
        em.getTransaction().commit();
        
        em.clear();
        
        List<Road> roads = em.createQuery("SELECT r FROM Road r", Road.class).getResultList();
        for (Road road : roads) {
            System.out.println(road.getId() + "= " + road.getName() + " " + road.getNumber());
        }
        List<Incident> incidents = em.createQuery("SELECT i FROM Incident i", Incident.class).getResultList();
        for (Incident incident : incidents) {
            System.out.println(incident.getId() + "= " + incident.getRoad().getId());
        }
    }
    
    private static Road findRoad(String name, Integer number, EntityManager em) {
        return em.createQuery("SELECT r FROM Road r WHERE name = :name AND number = :number", Road.class)
            .setParameter("name", name)
            .setParameter("number", number)
        .getSingleResult();
    }
    
}
```


----------



## Dit_ (6. Apr 2011)

Vielen Dank!

noch eine Frage,

ich habe zum Incident eine Beschreibung:


```
@Column(name = "DESCRIPTION", columnDefinition = "LONGTEXT")
	private String				description;
```

Problem ist nun, wenn die Beschreibung zu groß ist, >255 gibt es Fehlermeldung. 
Wie definiere ich richtig vom welchem typ eine Spalte sein soll?


----------



## Dit_ (6. Apr 2011)

Mein Manager sieht so aus:

```
public class DBManager {
	
	private static DBManager	_instance;
	
	/**
	 * 
	 */
	private DBManager() {
		//
	}
	
	/**
	 * @return the _instance
	 */
	public static final DBManager getInstance() {
		if (_instance == null) {
			_instance = new DBManager();
		}
		return _instance;
	}
	
	
	public void initDB() {
		
		AnnotationConfiguration cfg = new AnnotationConfiguration();
		cfg.addAnnotatedClass(DBIncident.class);
		cfg.addAnnotatedClass(DBLocation.class);
		cfg.addAnnotatedClass(DBRoad.class);
		cfg.configure();
		// SchemaExport exp = new SchemaExport(cfg);
		// exp.create(false, true);
	}
	
	
	/**
	 * Speichert neues Objekt in die DB.
	 * 
	 * @param newObj
	 *            neues Objekt.
	 */
	public void saveNewDBObject(Object... newObj) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		
		for (Object object : newObj) {
			session.save(object);
		}
		session.getTransaction().commit();
	}
}
```



```
public class HibernateUtil {



		private static final SessionFactory sessionFactory;

		static {
			try {
				AnnotationConfiguration cfg = new AnnotationConfiguration();
				cfg.addAnnotatedClass(DBIncident.class);
				cfg.addAnnotatedClass(DBLocation.class);
				cfg.addAnnotatedClass(DBRoad.class);
				
				sessionFactory = cfg.configure().buildSessionFactory();
			} catch (Throwable ex) {
				throw new ExceptionInInitializerError(ex);
			}
		}

		public static SessionFactory getSessionFactory() {
	        return sessionFactory;
	    }
}
```

Wie mache ich das mit 
	
	
	
	





```
EntityManager
```
 in deinem Beispiel :shock: 
bekomme Fehlermeldung: 
	
	
	
	





```
Could not find any META-INF/persistence.xml file in the classpath
```

Möchte wenns geht ohne XML auskommen.

gruß


----------



## mvitz (6. Apr 2011)

Wegen der Textbegrenzung an dein Description Feld @Lob, dann kann da mehr als 255 Zeichen rein.

Bezüglich deiner 2ten Frage ich nutze halt JPA und da wird die DB nun mal über die persistence.xml beschrieben. Habe da noch nie per Java konfiguriert.


----------

