# JSON abspeichern mit gleichen Datenbank Eintrag



## Damlo (17. Jan 2017)

Hallo zusammen,

ich stehe grade total auf dem Schlauch irgendwie.
Und deswegen bräuchte ich mal eure Hilfe bzw Rat.

Ich Arbeite mit Spring/JPA/Hibernate und benutze JACKSON um JSON "einzulesen".
Also ich bekomme per einer API eine JSON. Die beinhaltet induviduelle Genres. 
Diese Genres sollen gespeichert werden, aber nicht doppelt. Soweit klappt es auch, wenn ich das erste mal eine JSON entgegennehme und in die Datenbank übertrage. 
Sobald ich jetzt eine andere JSON nehme, aber eine der Genres gleich ist bekomme ich ein "duplicate entry" Fehler. 
Diesen bekomme ich aber irgendwie nicht weg. Bzw kriege es nicht hin das er alles andere trotzdem speichert nur doppelten Genres "überspringt".

Meine Methode zum speichern sieht wie folgt aus:


```
private List<String> getList(RedirectAttributes ra){
        URL url = null;
        Movie movie = null;
       
        List<String> list = new ArrayList<String>();
        ObjectMapper jsonMapper = new ObjectMapper();
        jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        Errors errors = null;
        try {
            url = new URL("https://api.themoviedb.org/3/movie/880?api_key=xxx&language=de");
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) {
                String jsonText = readAll(reader);
                movie = jsonMapper.readValue(jsonText, Movie.class);
                if(movie != null){
                    Movie savedMovie = movieDao.doSave( movie, errors );
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        } catch ( MalformedURLException e ) {
            e.printStackTrace();
        }
        return list;
    }
```

in dieser Zeile: 





> movie = jsonMapper.readValue(jsonText, Movie.class);


nimmt er die JSON entgegen. 

in dieser Zeile 





> Movie savedMovie = movieDao.doSave( movie, errors );


Speichert er das MovieObjekt. 

die movieDao ist meine Service klasse diese sieht so aus:

```
package com.miyava.movie.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.Errors;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.miyava.common.CrudDao;
import com.miyava.movie.model.Movie;
import com.miyava.movie.repository.MovieRepository;

@Service
public class MovieDao extends CrudDao<Movie, Long, MovieRepository> {

    @Autowired
    public MovieDao( MovieRepository repository ) {
        super( repository );
    }

    @Override
    public boolean validateOnSaveOrUpdate( Optional<Movie> oldEntity, Movie entity, Errors errors ) {
        if ( entity == null ) {
            return false;
        }

        if ( Strings.isNullOrEmpty( entity.getTitle() ) ) {
            errors.rejectValue( "movie", "movie.messages.movie_empty" );
            return false;
        }

        // Movie bereits vergeben?
        Movie tmpMovie = findOneByTitle( entity.getTitle() );
        if ( tmpMovie != null && !tmpMovie.getId().equals( entity.getId() ) ) {
            errors.rejectValue( "movie", "movie.messages.id_already_exists", new Object[] { entity.getTitle() }, null );
            return false;
        }

        return true;
    }

    @Override
    public boolean validateOnDelete( Movie entity, Errors errors ) {
        if ( entity != null ) {
            return true;
        }
        return false;
    }

    public Movie findOneByTitle( String title ) {
        return repository.findOneByTitle( title );
    }
}
```



Mein Model für Movies sieht so aus:

```
package com.miyava.movie.model;

import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.*;

import org.hibernate.validator.constraints.Length;
import org.springframework.data.jpa.datatables.mapping.DataTablesOutput;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.miyava.auditing.AuditedEntity;
import com.miyava.common.NotEmpty;
import com.miyava.genres.model.Genres;
import com.miyava.user.model.User;

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id")
@Entity
public class Movie
    extends AuditedEntity
    implements com.miyava.common.Entity<Long> {

    @Column( name = "movie_id" )
    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    @JsonView( DataTablesOutput.View.class )
    private Long id;

    @NotEmpty( message = "movie.messages.movie_empty" )
    @Column( nullable = false, unique = false, length = 255 )
    @Length( max = 255, message = "common.message.data_to_long" )
    @JsonView( DataTablesOutput.View.class )
    private String title;

    @NotEmpty( message = "movie.messages.description_empty" )
    @Column( nullable = false, unique = false)
    @Lob
    @JsonView( DataTablesOutput.View.class )
    private String overview;
   
    @NotEmpty( message = "movie.messages.movie_empty" )
    @Column( nullable = false, unique = false, length = 255 )
    @Length( max = 255, message = "common.message.data_to_long" )
    @JsonView( DataTablesOutput.View.class )
    private String status;

    @Column( unique = false, columnDefinition="DATETIME", name = "release_date" )
    @JsonView( DataTablesOutput.View.class )
    private Date release_date;
   
    @ManyToMany(cascade = CascadeType.ALL, targetEntity = Genres.class)
    @JoinTable(name = "movie_genres", joinColumns = @JoinColumn(name = "movie_id",referencedColumnName = "movie_id"),inverseJoinColumns = @JoinColumn(name = "genres_id", referencedColumnName = "genres_id"))
    @JsonView( DataTablesOutput.View.class )
    private List<Genres> genres;
   
    @ManyToMany(mappedBy = "movie")
    private Set<User> user;
   
    public Movie() {}

    public Long getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle( String title ) {
        this.title = title;
    }

    public String getOverview() {
        return overview;
    }

    public void setOverview( String overview ) {
        this.overview = overview;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus( String status ) {
        this.status = status;
    }

    public Date getRelease_date() {
        return release_date;
    }

    public void setRelease_date( Date release_date ) {
        this.release_date = release_date;
    }

    public List<Genres> getGenres() {
        return genres;
    }

    public void setGenres( List<Genres> genres ) {
        this.genres = genres;
    }

    public Set<User> getUser() {
        return user;
    }

    public void setUser( Set<User> user ) {
        this.user = user;
    }
   
}
```

Für die Genres so:

```
package com.miyava.genres.model;

import java.util.List;
import java.util.Set;

import javax.persistence.*;

import org.hibernate.validator.constraints.Length;
import org.springframework.data.jpa.datatables.mapping.DataTablesOutput;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.miyava.auditing.AuditedEntity;
import com.miyava.common.NotEmpty;
import com.miyava.movie.model.Movie;

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id")
@Entity
public class Genres
    extends AuditedEntity
    implements com.miyava.common.Entity<Long> {

    @Column( name = "genres_id" )
    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    @JsonView( DataTablesOutput.View.class )
    private Long id;

    @NotEmpty( message = "Das Feld darf nicht Leer sein!" )
    @Column( nullable = false, unique = true, length = 100 )
    @Length( max = 100, message = "Name ist zu lang" )
    @JsonView( DataTablesOutput.View.class )
    private String name;

    @ManyToMany(cascade = CascadeType.ALL, targetEntity = Movie.class)
    @JoinTable(name = "movie_genres",
    inverseJoinColumns = @JoinColumn(name = "movie_id",
            nullable = false,
            updatable = false),
    joinColumns = @JoinColumn(name = "genres_id",
            nullable = false,
            updatable = false))
    private List<Movie> movies;
   
    public Genres() {}

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public List<Movie> getMovie() {
        return movies;
    }

    public void setMovie(List<Movie> movies) {
        this.movies = movies;
    }
   
}
```

Ich dachte mir, dass ich nachdem ich die JSON eingelesen habe. Prüfe ob es die Genre schon gitb. Also habe ich movie.getGenres() ausgegegben aber dort bekomme ich nur sowas ausgegeben: 


> [com.miyava.genres.model.Genres@7344d30, com.miyava.genres.model.Genres@59ae8c24]


und komme irgendwie nicht an die richtigen Genrenamen. Ich geh davon aus das ich irgendwie ein denk fehler hab und deswegen da nicht drauf komme.

Selbst wenn ich da dran käme, müsste ich diesen Namen dann mit der findOneByName Methode von der GenresRepository klasse nutzen um an die ID zu kommen und diese ID dann dem vom JSON erzeugtem Objekt hinzufügen? würde er das dann noch überschreiben bzw was würde er dann machen?

Wäre der Ansatz richtig? oder gibt es da etwas einfacheres? 

Wenn der Ansatz richtig wäre, wie würdet ihr dann die Genres prüfen? und wie würde ich daran kommen? Also ich bin halt vom Namen ausgegangen aber wie würde ich da dran kommen dann?

Schon mal vielen Dank für die mühe mir zu Helfen!
Gruß Damlo


----------



## Joose (17. Jan 2017)

Damlo hat gesagt.:


> Ich dachte mir, dass ich nachdem ich die JSON eingelesen habe. Prüfe ob es die Genre schon gitb. Also habe ich movie.getGenres() ausgegegben aber dort bekomme ich nur sowas ausgegeben:
> 
> und komme irgendwie nicht an die richtigen Genrenamen. Ich geh davon aus das ich irgendwie ein denk fehler hab und deswegen da nicht drauf komme.


Hierbei handelt es sich um die "Speicheradresse"  ... um eine andere Ausgabe zu bekommen musst du die "toString()" Methode überschreiben.


----------



## Damlo (17. Jan 2017)

> Hierbei handelt es sich um die "Speicheradresse"  ... um eine andere Ausgabe zu bekommen musst du die "toString()" Methode überschreiben.



ach ich hab den Wald vor lauter Bäume nicht mehr gesehen.
Ja, natürlich. Danke für den Tipp. Jetzt klappt es auch.

Für die, die eventuell auch auf das Problem stoßen. So sieht mein Methode zum Speichern/Laden der JSON über die API aus:


```
private List<String> getList(RedirectAttributes ra){
        URL url = null;
        Movie movie = null;
      
        List<String> list = new ArrayList<String>();
        ObjectMapper jsonMapper = new ObjectMapper();
        jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        Errors errors = null;
        try {
            url = new URL("https://api.themoviedb.org/3/movie/880?api_key=xxxxxxxx&language=de");
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) {
                String jsonText = readAll(reader);
                movie = jsonMapper.readValue(jsonText, Movie.class);
                if(movie != null){
                  
                    for (Genres s : movie.getGenres()) {
                       if(genreDao.findOneByName(s.getName()) != null){
                           s.setId(  genreDao.findOneByName(s.getName()).getId() );
                       }
                    }
                    list.add( movie.getTitle() );
                    Movie savedMovie = movieDao.doSave( movie, errors );
                    if ( savedMovie != null ) {
                        //MessageHelper.addSuccessAttribute( ra, "common.message.success_create" );
                    }
                    else {
                        //MessageHelper.addErrorAttribute( ra, "nope" );
                    }
                }
              
            } catch (IOException e){
                e.printStackTrace();
            }
        } catch ( MalformedURLException e ) {
            e.printStackTrace();
        }
        return list;
    }
```


----------



## Thallius (17. Jan 2017)

Meinst du wirklich es ist so schlau deinen api key hier zu veröffentlichen? Also wenn ich lustig bin, dann schreibe ich jetzt einen BOT der 1000 Abfragen in der Sekunde macht und dann hast du den Ärger an der Backe....


----------

