【问题标题】:How to use graphql with jpa if schema is different to database structure如果架构与数据库结构不同,如何将 graphql 与 jpa 一起使用
【发布时间】:2020-06-12 20:35:08
【问题描述】:

有一个给定的数据库结构和 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
}

项目使用11.0版本的graphql-java(估计我们应该很快更新)

<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
}
}

那么如何摆脱 getGraphQlCowFromCowEntitygetGraphQlSheepFromSheepEntity。它使代码加倍,并且与 graphql 被认为是数据的抽象直接冲突。使用这种设计,每次通过 jpa 加载所有字段,而不仅仅是请求的字段。 想象一下,这是一个具有更多字段的更复杂的环境。

graphql 架构无法更改,因为这不是我的责任,更改整个后端以匹配架构也不是我想要归档的内容。

亲切的问候

【问题讨论】:

    标签: java jpa graphql graphql-java


    【解决方案1】:

    您应该使用 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 Tools: Map entity type to graphql type

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-08
      • 1970-01-01
      • 2020-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-12-28
      相关资源
      最近更新 更多