Hibernate a programowanie pod interfejsy

0

Hej,

Chciałbym się was doradzić czy możliwe jest programowanie w Javie "pod interfejsy" i jednocześnie używania Hibernate.
Poniżej mój problem jeżeli chodzi o łączenie poprawnego stylu programowania i tego frameworka:

Programując "pod klasy" - tzn nie używając interfejsów bardzo łatwo wszystko jest w Hibernate zmapować. Chciałbym jednak zrobić to nieco ładniej, co w przyszłości miało by mi ułatwić życie. Tylko okazuje się że to nie jest takie proste. Wymyśliłem sobie:

Interfejs Identifiable - jedyna metoda to ta, która pozwala na pobranie klucza głównego danego obiektu. Nie ma metody ustawiającej. Chciałbym aby taki klucz ustawiany był raz a potem nie zmieniany (zresztą niektóre bazy danych na to nie pozwalają). Hibernate będzie w stanie ten klucz ustawić przy tworzeniu obiektu bo dobierze się do pola odpowiedniej klasy. Tutaj tylko będzie pobieranie klucza:

public interface Identifiable {
    Long getId();
}

zaimplementujmy sobie relację many-to-many z użyciem interfejsów. Mamy graczy i drużyny - wiele graczy może grać w jednej drużynie, jeden gracz może grać w wielu drużynach. No to jazda:

public interface Player extends Identifiable {
    String getName();
    void setName(String name);
    Set<Team> getTeams();
    void setTeams(Set<Team> teams);
    void addTeam(Team team);
}

public interface Team extends Identifiable {
    String getName();
    void setName(String name);
    Set<Player> getPlayers();
    void setPlayers(Set<Player> players);
    void addPlayer(Player player);
}

public class PlayerImpl implements Player {

    // tutaj dopiero bedzie deklarowane id!!!
    private Long id;
    private String name;
    private Set<Team> teams;

    public PlayerImpl() {
    }

    public Set<Team> getTeams() {
        return teams;
    }

    public void setTeams(Set<Team> teams) {
        this.teams = teams;
    }

    public void addTeam(Team team) {
        teams.add(team);
    }

    public String getName() {
        return name;
    }

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


    public Long getId() {
        return id;
    }
}



public class TeamImpl implements Team {

    private Long id;
    private String name;
    private Set<Player> players;

    public TeamImpl() {
    }

    public Set<Player> getPlayers() {
        return players;
    }

    public void setPlayers(Set<Player> players) {
        this.players = players;
    }

    public void addPlayer(Player player) {
        players.add(player);
    }

    public String getName() {
        return name;
    }

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

    public Long getId() {
        return id;
    }
}

i teraz jest pytanie jak to zmapować?
Próbuję tak:

<?xml version="1.0" ?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"  >

<hibernate-mapping>   

    <class name="PlayerImpl" table="PLAYERS">
        <id name="id" column="ID" access="field">
            <generator class="sequence">
                <param name="sequence">PLAYERS_SEQUENCE</param>
         </generator>
        </id>

        <property name="name" column="NAME"/>

        <!-- many-to-many relationship -->
        <set name="teams" table="PLAYERS_TEAMS">
            <key column="PLAYER_ID"/>
            <many-to-many column="TEAM_ID" class="Team"/> <!-- tutaj podalem interfejs! pojdzie? -->
        </set>
    </class>

    <class name="TeamImpl" table="TEAMS">
        <id name="id" column="ID" access="field">
            <generator class="sequence">
                <param name="sequence">TEAMS_SEQUENCE</param>
            </generator>
        </id>

        <property name="name" column="NAME"/>

        <!-- many-to-many relationship -->
        <set name="players" table="PLAYERS_TEAMS">
            <key column="TEAM_ID"/>
            <many-to-many column="PLAYER_ID" class="Player"/> <!-- tutaj takze interfejs -->
        </set>
    </class>

</hibernate-mapping>

Niestety, nie za bardzo chce to współpracować. Drze się, że nie zmapowałem interfejsów.
Tylko tutaj staje pod ścianą bo nie zawsze da się zmapować interfejs (w obie strony oczywiście - tworzenie i zapisywanie z / do bazy). Dlaczego - otóż wynik działania jakiejś metody z interfejsu może być wynikiem działania wielu metod z implementującej go klasy (jakieś dodawania pól chociażby).

Albo lepiej - przykład z góry - mój interfejs nie zawiera żadnego pola które można by uznać za jego klucz głowny - więc hibernate nie pozwoli mi tego zmapować. Nie chce w interfejsie umieszczać pola "id", bo było by one publiczne i ogólnie dostępne jadąc w dół po całej hierarchii...

Czy w ogóle taki styl programowania w Hibernate jest możliwy? Z tego co oglądam jakieś opensourcowe projekty oparte na Hibernate to raczej wszyscy jadą w nich "pod klasy".

Pozdrawiam!

0

W hibernate nie można mapować interfejsów, a jedynie klasy. Możesz jednak zamiast mapowania w XMLu wykorzystać adnotacje i powinno działać.

0

Dziękuję za odpowiedź!

To, że nie można mapować interfejsów wg mnie ma (miało by) sens - to sprawa klasy jak ona ma zamiar przygotować wynik wywołania metody. Że połączy 10 pól zmapowanych z bazy danych - interfejsu to nie powinno obchodzić. Dlatego gdyby w Hibernate nie było takiej możliwości to było by to całkiem ok.

Ale z drugiej strony to nie jestem taki pewien czy tej możliwości nie ma. Zobacz tutaj:
http://community.jboss.org/wiki/MappingaDynamicProxy

Wiem że to nie ten konkretny przypadek, ale jednak zmapowali interfejs :)

I moja prośba: czy mógłbyś dać przykład jak to rozwiązać za pomocą adnotacji (z tego co ja umiem na ten temat - a przyznam się że umiem niezbyt dużo - to mapowanie za pomocą XML czy adnotacji w efekcie na to samo wychodzi).

Pozdrawiam,
Piotrek


ok i drugie pytanie ;)
weźmy, że w XML nie da się mapować interfejsów. Zatem mając taką strukturę programu jak w pierwszym poście, w pliku XML musiałbym napisać:

 <set name="teams" table="PLAYERS_TEAMS">
            <key column="PLAYER_ID"/>
            <many-to-many column="TEAM_ID" class="TeamImpl"/> <!-- konkretna implementacja -->
        </set>

Tylko teraz mamy niespójność - bo jeżeli w tym Set<Team> w kodzie Javy podstawie inna implementację Team (z punktu widzenia kodu Javy będzie to ok) i potem będę chciał to zmapować to Hibernate może się wysypać....

0

Hm... tutaj wykorzystano "dziedziczenie" i potraktowano interfejs jako klasę "wirtualną", ale klasę. Spróbuj. Hibernate pozwala na mapowanie struktury klas. Powinno zaskoczyć.
Co do 2. No niestety może... są plusy dodatnie i plusy ujemne...

1 użytkowników online, w tym zalogowanych: 0, gości: 1