Как использовать graphql с jpa, если схема отличается от структуры базы данных - PullRequest
0 голосов
/ 28 февраля 2020

Существует заданная структура базы данных и схема graphql. К счастью, у них много общего, но, к сожалению, есть некоторые различия. Допустим, в java есть объекты, соответствующие следующей структуре базы данных.

SQL:

TABLE ANIMAL
+ID NUMBER(19)
+NR_OF_LEGS NUMBER(19)

TABLE SHEEP
+ID NUMBER
+LAST_TIME_SHEARED DATETIME
+ANIMAL_ID NUMBER(19)

TABLE COW
+MILK_IN_L NUMBER(3)
+ANIMAL_ID NUMER(19)

Java:

@Entity
@Table(name = "ANIMAL")
public class Animal

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@Column(name="nrOfLegs", nullable=false)
private long nrOfLegs;
}


@Entity
@Table(name = "SHEEP")
public class SheepE

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@Column(name="lastTimeSheared", nullable=false)
private Datetime lastTimeSheared;

@ManyToOne(targetEntity = AnimalE.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "animalId", nullable = false, insertable = false, updatable = false)   
private Animal animal;
}


@Entity
@Table(name = "COW")
public class CowE

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@Column(name="milkInL", nullable=false)
private int milkInL;

@ManyToOne(targetEntity = AnimalE.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "animalId", nullable = false, insertable = false, updatable = false)   
private Animal animal;
}

Существующие Схема GraphQl считается такой:

type Sheep{
id: int!
lastTimeSheard: String!
nrOfLegs: int!
}

type Cow {
id: int!
milkInL: int!
nrOfLegs: int
}

В проекте используется graphql- java в версии 11.0 (думаю, что мы должны обновить в ближайшее время)

<dependency>
  <groupId>com.graphql-java</groupId>
  <artifactId>graphql-java</artifactId>
  <version>11.0</version>
</dependency>

Graphql работает нормально и Вот так:

@Component
public class GraphQLProvider {
    @Autowired
    GraphQLDataFetchers graphQLDataFetchers;

    private GraphQL graphQL;

    @PostConstruct
    public void init() {this.graphQL = /*init;*/null;}

    private RuntimeWiring buildWiring() {
        RuntimeWiring.Builder b = RuntimeWiring.newRuntimeWiring()
                .type(TypeRuntimeWiring.newTypeWiring("Query")
                        .dataFetcher("freightCarrier", graphQLDataFetchers.getCow()))
                .type(TypeRuntimeWiring.newTypeWiring("Query")
                        .dataFetcher("personCarrier", graphQLDataFetchers.getSheep())));
        return b.build();
    }
}

@Component
public class GraphQLDataFetchers {
@AutoWired
private CowRepository cowRepo;
@AutoWired
private sheepRepository sheepRepo;

public DataFetcher getCow() {
        DataFetcher dataFetcher = (DataFetchingEnvironment dfe) -> {
            int id = dfe.getArgument("id");
            return getGraphQlCowFromCowEntity(cowRepo.getById(id));//dirty!
        };
        return dataFetcher;
    }

public DataFetcher getCow() {
        DataFetcher dataFetcher = (DataFetchingEnvironment dfe) -> {
            int id = dfe.getArgument("id");
            return getGraphQlSheepFromSheepEntity(cowRepo.getById(id));//dirty!
        };
        return dataFetcher;
    }

private Cow getGraphQlCowFromCowEntity(CowE ce){//dirty!
  return new Cow(ce.getId(), ce.getMilkInL(),ce.getLegs());
}

private Sheep getGraphQlSheepFromSheepEntity(SheepE se){//dirty!
  return new Sheep(se.getId(), se.getLastTime(),se.getLegs());
}
public class Sheep

private long id;
private Datetime lastTimeSheared;
private int nrOfLegs;
public Sheep(long id, DateTime lasttimeSheared, int nrOfLegs){
//u know what happens here
}
}

public class Cow

private long id;
private int milkInL;
private int nrOfLegs;
public Sheep(long id, int milkInL, int nrOfLegs){
//u know what happens here
}
}

Как избавиться от getGraphQlCowFromCowEntity и getGraphQlSheepFromSheepEntity . Это удваивает код, а также находится в прямом противоречии с тем, что graphql считает абстракцией данных. При таком дизайне здесь каждый раз все поля загружаются через jpa, а не только запрошенные поля. Представьте, что это намного более сложная среда с большим количеством полей.

Схема graphql не может быть изменена, так как это не моя ответственность, поэтому изменение всей серверной части в соответствии со схемой также не то, что я хочу архивировать.

С уважением

1 Ответ

0 голосов
/ 02 марта 2020

Вы должны использовать DTO. Извлечение и отправка объекта-сущности является плохой практикой, поскольку вы не хотите, чтобы ваш grahql api менялся каждый раз, когда вы проводите рефакторинг вашей модели базы данных или в вашем случае. Ваши объекты Sheep и Cow являются DTO, но вам понадобится какой-то способ преобразовать вашу сущность в DTO (getGraphQlCowFromCowEntity хорошо, но вы можете использовать полиморфизм - CowEntity.toDTO() - или иметь сервисный слой для преобразования, существует множество способ сделать это).

Чтобы ответить на ваши вопросы о загрузке только запрошенных данных, вы хотите, чтобы ваш объект DTO был заполнен только запрошенными полями. Один из способов сделать это - вместо того, чтобы заполнять все поля, иметь DTO собственную ссылку на объект-сущность и извлекать данные из объекта-сущности только по запросу.

public class Sheep {

    private SheepE entity;
    public Sheep(SheepE entity){
        this.entity=entity;
    }

    public getId() {
        return entity.getId();
    }

    public getLastTimeSheared() {
        return entity.getLastTimeSheared();
    }
    ...
}

Пожалуйста, посмотрите ответ, который я написал на похожий вопрос: Инструменты Graphql: сопоставить тип сущности с типом graphql

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...