2017-12-24 10 views
0

Ich arbeite derzeit an der Entwicklung einer einfachen Java-Webanwendung ohne Verwendung eines ORM.Lazy Loading in benutzerdefinierten ORM

Es ist eine geschichtete Architektur. Ich verwende Annotationen, um die Spalten meiner Domain-Klasse in meine Persistenz-Ebene zu "mappen", in der sich die Repositories befinden.

Meine DefaultRepository verwendet Reflektion, um die Feldnamen zu erhalten und die Abfragen zu erstellen. Ich benutze nur dieses, anstatt ein separates für jede Domäne (wie Benutzer, Bestellung, Produkt) zu machen.

Es sieht wie folgt aus:

Repository:

public abstract class DefaultRepository <TYPE extends DefaultDomain<TYPE>>{ 

    public int insert(Connection con, TYPE entity){}; 
    public int update (Connection con, TYPE entity){}; 
    public int delete (Connection con, TYPE entity){}; 
    public int findById(Connection con, int id){}; 
    ... 

} 

ich faul Laden implementieren möchten nur die Aufträge jedes Benutzers zu laden, wenn angefordert. Dies geschieht vorzugsweise im Repository in der , wo ich die Ergebnismenge auf meine TYPE (Domain-Klasse) zuordnen.

Wie würde ich diese Fremdschlüsselbeziehung/eins zu vielen/vielen zu einem allgemein implementieren?

Eine Idee war, eine Annotation mit dem spezifischen Repository zu machen und dann die findAll() Methode aufzurufen, wenn die Orderliste aufgerufen wird.

Zum Beispiel:

public class Order extends DefaultDomain{ 
    @ManyToOne(repository=UserRepository.class) 
    private User user; 

} 

Ist das der richtige Weg? Gibt es einen anderen/besseren Ansatz?

+2

Sie ein ORM verwenden. Sie entscheiden sich dafür, Ihre eigenen zu schreiben. Die Anmerkungen, die Sie geschrieben haben, sind genau diejenigen, die JPA verwendet. – duffymo

+0

Ja danke, ich habe es schlecht formuliert. Ich habe versucht, herauszufinden, wie JPA/Hibernate das macht, konnte aber nichts Code finden, nur wie man es benutzt. – user9136913

+0

Sie können JPA-Annotation @ManyToOne verwenden (Fetch = FetchType.LAZY) – Mazen

Antwort

-1

Ich entwickelte eine Lösung wie diese, die ich in meinem Fall die mit CGLib kombiniert Proxy Design Pattern verwendet.

Im Grunde werden Sie Ihre Objekte durch eine Factory instanziieren, die Proxies generieren wird, die persistente Objekte von ORM zurückgeben und automatisch Listener erstellen, die die Methoden verwalten, die Sie verwalten möchten. Ich hoffe, das hilft dir.

https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html

public interface PersonInterface{ 
    public String getName(); 
    public void setName(String name); 
    public int findById(int id); 
} 
public static class Person implements PersonInterface{ 

    String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @Override 
    public int findById(int id) { 
     return id; 
    } 
} 
public static class ProxyPersonImpl implements java.lang.reflect.InvocationHandler{ 

    private PersonInterface person; 

    public ProxyPersonImpl(Person person) { 
     this.person = person; 
    } 
    public static PersonInterface newInstance(Person obj) { 
     return (PersonInterface) java.lang.reflect.Proxy.newProxyInstance(
      obj.getClass().getClassLoader(), 
      obj.getClass().getInterfaces(), 
      new ProxyPersonImpl(obj)); 
    }  
    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     System.out.println("My Proxy listen this method invocation:"+method.getName()); 
     return method.invoke(person, args); 
    } 
} 

public class ProxyTest { 
    public static void main(String[] args) { 
     PersonInterface p = ProxyPersonImpl.newInstance(new Person()); 
     p.setName("Name seted"); 
     String name = p.getName(); 
     System.out.println(name); 
     int i = p.findById(1); 
     System.out.println(i); 
    } 
} 
class Repository { 
    Connection con; 
    public Repository() { 
     con = ConnectionFactory.getConnection(); 
    } 

    public Person findById(int id) { 
     Person p = new Person(); 
     try { 
      PreparedStatement statement = con.prepareStatement("Your sql here"); 
      ResultSet result = statement.executeQuery();     
      if(result.next()) { 
       p.setName(result.getString("Name")); 
      }   
     } catch (SQLException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return p; 
    }  
} 

static class ConnectionFactory { 
    private static Connection con; 

    public static Connection getConnection() { 
     if(con == null) { 
      //create connection here 

     } 
     return con; 
    }  
} 
+0

Vielen Dank, ich bin mir nicht sicher, wie dieses Muster wird mir aber helfen. Ich weiß bereits, wie man die Methoden bekommt, und es wäre kein Problem, wenn ich kein "Standard" -Repository erstellen und stattdessen Repositories für jede Domain erstellen möchte. – user9136913

+0

Ich habe die Antwort zur Klärung bearbeitet. Wenn Sie eine Lazy- und eine Lade-Steuerung durchführen möchten, benötigen Sie einen Listener für den Methodenaufruf. Wenn die Methode aufgerufen wird, können Sie eine Entscheidung treffen, beispielsweise Daten aus der Datenbank laden. Um dies zu tun, müssen Sie ändern, wie Sie mit persistenten Objekten umgehen. –

+0

Ich denke, Sie können Ihre Anotierung so verbessern, @ManyToOne (repository = UserRepository.class, faul = true) –