# H2 - Long um eins falsch



## krgewb (10. Feb 2021)

Ich habe eine H2-Datenbank mit einer Tabelle namens Project.
Die Id (long) endet mit 80, aber wenn ich sie aus der DB hole und ausgebe, endet sie mit 81.

Ausschnitt aus dem RestController:

```
@RequestMapping(value = "get_projects", method = RequestMethod.POST)
public List<ProjectDTO> get_projects(HttpSession session) {
    logger.info("ProjectRestController.get_projects() called");
    return service.findAllProjects();
}
```


----------



## Flown (10. Feb 2021)

What?


----------



## thecain (10. Feb 2021)

Wie sollen wir an dem Stück Code das Problem sehen? und warum ist ein "findAll" Aufruf ein POST?


----------



## mrBrown (10. Feb 2021)

Ganz spontan: irgendwo hast du wahrscheinlich irgendwas falsch gemacht  Warum bist du dir denn sicher, dass die ID auf 80 und nicht doch auf 81 endet?


Du könntest über die h2-Web-Console mal direkt die Datenbank ansprechen, was genau dort hinterlegt ist. Ansonsten wären zumindest die SQL-Querys und die Entitäten interessant, der Controller hilft da am wenigsten


----------



## krgewb (11. Feb 2021)

Ich habe das Problem auch ohne H2. Bei H2 ist es aber krasser. Die ID ist z.B.  2056919897295828992, aber da steht 2056919897295829000.




```
import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "project")
public class ProjectEntity {

    @Id
    private Long id;

    @Column(name = "caption", nullable = false)
    private String caption;

    public Long getId() {
        return id;
    }

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

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }

    @Transient
    public static ProjectEntity loadFromDTO(ProjectDTO dto) {
        ProjectEntity entity = new ProjectEntity();
        entity.setId(dto.getId());
        entity.setCaption(dto.getCaption());
        return entity;
    }

}
```


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

public class ProjectDTO implements Serializable {

    private Long id;
    private String caption;

    public Long getId() {
        return id;
    }

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

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }
}
```


```
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProjectRepository extends JpaRepository<ProjectEntity, Long> {

}
```


```
@Override
public List<ProjectDTO> findAllProjects() {
    List<ProjectEntity> result = projectRepository.findAll();
    return ProjectWrapper.toDTO(result);
}
```


```
@POST
@Path("get_projects")
void get_projects(UsermanagementAbstractDisplayCallback<List<ProjectDTO>> async);
```


```
import java.util.ArrayList;
import java.util.List;

public class ProjectWrapper {

    public static List<ProjectDTO> toDTO(List<ProjectEntity> entities) {
        List<ProjectDTO> dtos = new ArrayList<>();
        for (ProjectEntity entity : entities) {
            dtos.add(ProjectWrapper.toDTO(entity));
        }
        return dtos;
    }

    public static ProjectDTO toDTO(ProjectEntity entity) {
        if (entity == null) {
            return null;
        }
        ProjectDTO dto = new ProjectDTO();
        dto.setId(entity.getId());
        dto.setCaption(entity.getCaption());
        return dto;
    }

}
```


----------



## mrBrown (11. Feb 2021)

krgewb hat gesagt.:


> Die ID ist z.B. 2056919897295828992, aber da steht 2056919897295829000.


*Warum* bist du der Meinung, dass die *ID eigentlich *`2_056_919_897_295_828_992`* ist*?
*Wo* steht `2_056_919_897_295_829_000`?
*Wie* schreibst du *in die Datenbank*?


Einfach blind hingeklatschter Java-Code ist dabei keine Hilfe. Entweder ein ganzes, *ausführbares Projekt, mit dem man den Fehler nachstellen kann* – oder *detaillierte Antworten auf gestellte Fragen*.


----------



## LimDul (11. Feb 2021)

Ergänzend - die ID ist nicht als GeneratedValue annotiert (und hat dementsprechend einen setter). Wann und wo wird überall dieser Setter aufgerufen. Denn im DTO wird das drinstehen, was in der Entität drinsteht. 

Dadurch das kein GeneratedValue dran steht, musst du ja irgendwo selber implementiert haben, wie die ID gesetzt wird. Und entweder wird die Methode zu oft oder nicht korrekt aufgerufen. Gibt es einen Grund Long zu nehmen und denn nicht als GeneratedValue zu setzen? 

Gefühlt hat man damit zwar den Vorteil, dass ich eine ID habe, bevor es persistiert ist, aber auch immense Nachteile:  Ich muss selber sicherstellen, dass die IDs konsistent sind, auch ggf. bei Clusterung, Neustarts, Multi-Threading etc.

Normalerweise kenne ich so - entweder Long + GeneratedValue oder Selber Setzen als UUID.


----------



## krgewb (11. Feb 2021)

> Wo steht 2_056_919_897_295_829_000?


In den Entwicklerwerkzeugen von Firefox unter Netzwerkanalyse -> get_projects -> Antwort.

@LimDul
Ich erstelle den Long-Wert per Zufall. In Zukunft versuche ich es mit Strings und UUID. Ich möchte aber trotzdem meinen Fehler verstehen.

Es ist zwar absolut möglich, aber sehr unwahrscheinlich, dass so viele der zufällig erzeugten Werte mit 000 enden.

```
long randomNumber = 1 + (long) (Math.random() * (Long.MAX_VALUE - 1));
```

Ich schreibe im Backend wie folgt in die Datenbank:

```
@Override
public void saveProjectEntry(ProjectDTO dto) {
    projectRepository.save(ProjectEntity.loadFromDTO(dto));
}
```

Ich wollte gerade mit IntelliJ in die Datenbank schauen, aber meine Zugangsdaten werden plötzlich nicht mehr akzeptiert.
User: sa
Password:
URL: jdbc:h2:~/test

Die Anwendung kann aber auf die Datenbank zugreifen. In der application.properties steht:

```
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:file:~/test;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
```


----------



## mrBrown (11. Feb 2021)

Ignorierst du die relevanten Fragen mit Absicht?


----------



## krgewb (11. Feb 2021)

👎 Ich habe deine Fragen beantwortet! Ich werde jetzt nichts mehr schreiben!


----------



## mrBrown (11. Feb 2021)

Ne, du hast bisher kein Mal gesagt, woher du die "ID die es eigentlich sein sollts" kennst. Du hast nur mehrmals erwähnt, dass nur die falsche angezeigt wird, aber woher du die richtige kommst oder weißt, dass die richtige anders ist, hast du bisher verschwiegen.


----------



## LimDul (11. Feb 2021)

An welcher Stelle im Programmablauf ist welche ID vorhanden. Die Aussage fehlt.

Dein gezeigter Code sagt - in der DB wird die ID gespeichert, die im DTO steht. Du sagst nein, aber woher kommt diese Info?
Soweit ich das sehe wird eine per Request übergebene Entität gespeichert

* Welcher Request wird abgeschickt? Welche ID steht in dem Request?
* Welche ID steht im DTO?
* Welche ID steht in der Entität?
* Welche ID steht in der Datenbank


----------



## kneitzel (11. Feb 2021)

krgewb hat gesagt.:


> Ich erstelle den Long-Wert per Zufall. In Zukunft versuche ich es mit Strings und UUID. Ich möchte aber trotzdem meinen Fehler verstehen.


Das scheint mir ein sehr schlechter Weg zu sein. Für kleine Tests oder Spielereien mag die Chance, eine ID doppelt zu haben, zwar gering zu sein, aber da könnte man auch jede andere vernünftige ID vergeben.

Aber das nur am Rande ans Anmerkung.


----------



## krgewb (19. Mrz 2021)

Ich habe einen neuen Thread mit einem Minimalbeispiel eröffnet.
https://www.java-forum.org/thema/long-wird-gerundet.191461/


----------

