# Data Access Object | Java



## _Truck_ (20. August 2007)

Hallo,

ich brauche dringends eine helfende Hand im Thema DAO in Java.
Im Internet konnte ich leider nichts genauers finden.

Ich möchte wissen:
- (was ?)
- genaue Implementierung ?
- weiteres Wissenwertes

Bin für jede Quelle und Erklärung dankbar !


Gruß Truck


----------



## zerix (20. August 2007)

Hallo,

ein DAO wird verwendet um die Persistenz-Schicht von der Geschäftslogik zu trennen. So lässt sich die Persistenz-Schicht am leichtest austauschen. Angenommen du nutzt Hibernate und möchtest auf Toplink umstellen. Wenn du das ohne eine solche Dao-Schicht machst wirst du Probleme dabei haben.

Beispiel (wurde TopLink verwendet):

Business-Object

```
package empprojekt.model;

import java.io.Serializable;
import java.util.Date;

import oracle.toplink.indirection.ValueHolder;
import oracle.toplink.indirection.ValueHolderInterface;

public class Employee implements Serializable {

	private static final long serialVersionUID = 1L;

	private ValueHolderInterface mgr = null;

	private String ename = null;

	private String job = null;

	private Long empno = null;

	private Date hireDate = null;

	private Integer sal = null;

	private Integer comm = null;

	private Integer deptno = null;

	public Employee() {
	}

	public Employee(Employee mgr, String ename, String job, Date hireDate,
			Integer sal, Integer comm, Integer deptno) {
		super();
		this.mgr = new ValueHolder(mgr);
		this.ename = ename;
		this.job = job;
		this.hireDate = hireDate;
		this.sal = sal;
		this.comm = comm;
		this.deptno = deptno;
	}

	public Integer getComm() {
		return comm;
	}

	public void setComm(Integer comm) {
		this.comm = comm;
	}

	public Integer getDeptno() {
		return deptno;
	}

	public void setDeptno(Integer deptno) {
		this.deptno = deptno;
	}

	public Long getEmpno() {
		return empno;
	}

	public String getEname() {
		return ename;
	}

	public void setEname(String ename) {
		this.ename = ename;
	}

	public Date getHireDate() {
		return hireDate;
	}

	public void setHireDate(Date hireDate) {
		this.hireDate = hireDate;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	public ValueHolderInterface getMgr() {
		return mgr;
	}

	public void setMgr(Employee mgr) {
		if (this.mgr == null) {
			this.mgr = new ValueHolder();
		}
		this.mgr.setValue(mgr);
	}

	public Integer getSal() {
		return sal;
	}

	public void setSal(Integer sal) {
		this.sal = sal;
	}

	public String toString() {
		return ename;
	}

}
```

Du solltest dir erstmal ein Interface implementieren, mit möglichst allgemeinen Methoden die du brauchen wirst. Durch dieses Interface lässt sich nachher alles leicht austauschen, wenn du nur auf dem Interface arbeitest.


```
package empprojekt.dao;

import java.util.Collection;
import java.util.Map;

import empprojekt.model.Employee;

public interface EmpDao {
	
	public Employee findByPriKey(Long key) throws DaoException;

	public Collection findAll()throws DaoException;
	
	public Collection genericFinder(Map map)throws DaoException;
	
	public Employee insert(Employee employee)throws DaoException;
	
	public Employee update(Employee employee)throws DaoException;
	
	public void delete(Employee employee)throws DaoException;
	
	public void initialize()throws DaoException;
	
	public void close()throws DaoException;
}
```

Hier mal eine Implementation zu dem Interface, also die eigentliche Persistenz-Schicht

```
package empprojekt.dao;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import oracle.toplink.expressions.ExpressionBuilder;
import oracle.toplink.queryframework.ReadAllQuery;
import oracle.toplink.queryframework.ReadObjectQuery;
import oracle.toplink.sessions.Session;
import oracle.toplink.sessions.UnitOfWork;
import oracle.toplink.threetier.ClientSession;
import oracle.toplink.threetier.ServerSession;
import oracle.toplink.tools.sessionconfiguration.XMLSessionConfigLoader;
import oracle.toplink.tools.sessionmanagement.SessionManager;
import empprojekt.model.Employee;

public class EmpDaoToplinkImpl implements EmpDao {

	private ServerSession server = null;

	private ClientSession clientSession = null;

	protected EmpDaoToplinkImpl() {

	}

	@SuppressWarnings("deprecation")
	public void delete(Employee employee) throws DaoException {
		UnitOfWork uow = clientSession.getActiveUnitOfWork();

		if (uow == null) {
			uow = clientSession.acquireUnitOfWork();
		}

		uow.deleteObject(employee);

		uow.commit();

		uow.release();
	}

	@SuppressWarnings("deprecation")
	public Collection findAll() throws DaoException {

		Collection col = clientSession.readAllObjects(Employee.class);
		UnitOfWork uow = clientSession.acquireUnitOfWork();
		
		col = uow.registerAllObjects(col);
		
		uow.release();
		
		return col;
	}

	@SuppressWarnings("deprecation")
	public Employee findByPriKey(Long key) throws DaoException {

		ReadObjectQuery query = new ReadObjectQuery(Employee.class);
		query.setSelectionCriteria(new ExpressionBuilder().get("empno").equal(
				key));

		Employee emp = (Employee) clientSession.executeQuery(query);

		UnitOfWork uow = clientSession.acquireUnitOfWork();

		uow.registerObject(emp);

		uow.release();

		return emp;
	}

	@SuppressWarnings(value = { "unchecked", "deprecation" })
	public Collection genericFinder(Map map) throws DaoException {
		ExpressionBuilder builder = new ExpressionBuilder();

		Set<String> keySet = map.keySet();
		Expression expression = null;
		for (String key : keySet) {
			if (expression == null) {
				expression = builder.get(key).equal(map.get(key));
				continue;
			}
			expression = expression.and(builder.get(key).equal(map.get(key)));
		}

		return clientSession.readAllObjects(Employee.class, expression);
	}

	@SuppressWarnings("deprecation")
	public Employee insert(Employee employee) throws DaoException {
		UnitOfWork uow = clientSession.getActiveUnitOfWork();

		if (uow == null) {
			uow = clientSession.acquireUnitOfWork();
		}

		employee = (Employee) uow.registerObject(employee);

		uow.commit();

		uow.release();

		return employee;
	}

	@SuppressWarnings("deprecation")
	public Employee update(Employee employee) throws DaoException {
		UnitOfWork uow = clientSession.getActiveUnitOfWork();

		if (uow == null) {
			uow = clientSession.acquireUnitOfWork();
		}

		employee = (Employee) uow.deepMergeClone(employee);

		uow.commit();

		uow.release();

		return employee;
	}

	@SuppressWarnings("deprecation")
	public void close() throws DaoException {
		SessionManager.getManager().destroySession(clientSession.getName());
	}

	@SuppressWarnings("deprecation")
	public void initialize() throws DaoException {

		XMLSessionConfigLoader loader = new XMLSessionConfigLoader(
				"Scottsessions.xml");
		SessionManager mgr = SessionManager.getManager();

		server = (ServerSession) mgr.getSession(loader, "Session", Thread
				.currentThread().getContextClassLoader());

		clientSession = server.acquireClientSession();
	}

	protected Session getSession() {
		return clientSession;
	}

}
```

Damit das ganze auch austauschbar bleibt wird das ganze über eine Factory erzeugt. So brauchst nachher nur die Factory zu ändern, was sich dann auf eine Zeile beläuft.

```
package empprojekt.dao;

public class EmpDaoFactory {

	private static EmpDaoFactory instance = null;
	
	private EmpDaoFactory() {
	}
	
	public EmpDao getEmployeeDao(){
		EmpDao impl = new EmpDaoToplinkImpl();
		return impl;
	}
	
	public static EmpDaoFactory getInstance(){
		if(instance == null){
			instance = new EmpDaoFactory();
		}
		return instance;
	}
	
}
```

Da ja je nachdem was du in deiner Persistenz-Schicht nutzt, immer andere Exceptions geworfen werden können, solltest du dir auch eine eigene Exception machen, damit du dich nicht durch die Exceptions abhängig machst.


```
package empprojekt.dao;

public class DaoException extends Exception {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6379475486812757206L;

  public DaoException()
  {
    super();
  }

  public DaoException(String message, Throwable cause)
  {
    super(message, cause);
  }

  public DaoException(String message)
  {
    super(message);
  }

  public DaoException(Throwable cause)
  {
    super(cause);
  }

}
```

So kannst du dann wenn eine Exception in deiner Persistenz-Schicht auftritt, sie einfach weiterleiten


```
try{
}
catch(ToplinkException e)
{
throw new DaoException(e);
}
```

Nachher brauchst du einfach nur noch die Implementation auszutauschen und eine Zeile in der Factory zu ändern und schon hast du die Komplette Persistenz-Schicht ausgetauscht.
Ich hoffe das ganze hilft dir erstmal.

MFG

zEriX


----------



## Thomas Darimont (20. August 2007)

Hallo,

für simple CRUD (Create, Read, Update, Delete) Operationen bietet es sich an ein generisches DAO zu erzeugen und das für diese einfachen Datenzugriffe immer wieder zu verwenden:

Siehe:
http://www.tutorials.de/forum/j2ee/283835-strukturierung-webanwendung.html

Nur für spezielle Anlege / Such / Filter Operation würde ich von diesem generischen DAO Ableiten und eine spezielle Implementierung definieren.

Weiterhin ist dieser gezeigte Factory Ansatz in seiner flexibilität doch beschränkt. Jedes mal wenn ich eine neue DAO Implementierung erzeugt habe muss ich auch die Factory anpassen. Besser wäre es hier eine flexible ObjectFactory zu haben die man extern Konfigurieren kann. Eine Möglichkeit wäre beispielsweise die Konfiguration der Services (das ausstatten der Services mit entsprechenden DAO's) über das Spring Framework / Guice oder einen sonstiges Dependency Injection  Framework durchzuführen. Damit spart man sich das lässtige schreiben eigener ObjectFactories...

Gruß Tom


----------



## zerix (20. August 2007)

@Tom

Bei meinem Beispiel kann man sicherlich noch einiges besser machen, es war halt nur ein Beispiel. 
Der generische Ansatz ist natürlich der wesentlich bessere.

MFG

zEriX


----------



## _Truck_ (21. August 2007)

Ok danke Euch beiden,
ich werde es bald mal ausprobieren, werde bei Problemen sicherlich auf diesen zurückgreifen !


Gruß Truck


----------



## _Truck_ (24. August 2007)

Kann in einem DAO auch einfach nur einen SAXBuilder stehen ?
Und was muss zwingend in ein DAO ?

Danke,

Gruß Truck


----------



## zerix (24. August 2007)

Was in der entgültigen Implementation des DAOs steht ist deine Sache. Du kannst das ganze auch nur in eine Textdatei abspeichern, wenn du das möchtest. 



> für simple CRUD (Create, Read, Update, Delete) Operationen bietet es sich an ein generisches DAO zu erzeugen und das für diese einfachen Datenzugriffe immer wieder zu verwenden:



Also ich würde sagen, dass sowas schon enthalten sein müsste. Wenn das alles drin ist, kannst du darauf aufbauen und eventuell alles noch spezialisieren.

MFG

zErix


----------

