当前位置: 首页 > 知识库问答 >
问题:

如果模式与数据库结构不同,如何将graphql与jpa结合使用

苏君昊
2023-03-14

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

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

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

问候

共有1个答案

宦博雅
2023-03-14

您应该使用DTO。检索和发送实体对象是一种不好的做法,因为您不希望每次重构数据库模型时或在您的情况下GrahQLAPI都发生更改。您的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类型

 类似资料:
  • 我使用的是java 8、spring boot 2.0.0、spring data jpa(spring boot starter data jpa)、gradle和intellij。我一直在尝试使用JPA元模型,但很难找到如何配置。 实体类的元模型不仅仅是生成的。 我猜到它会很简单,但现在看来,这可能是错误的。我该如何使用它?

  • 到目前为止,我已经编写了两个rails应用程序,这无疑让我对ruby rails非常满意。但我不能对C说同样的话。我甚至不知道我在看什么,说实话,每次我看C的时候,它看起来像通心粉。 我正在尝试构建一个spotify web应用程序。web API太差劲了,所以我不得不用这个:https://developer.spotify.com/technologies/libspotify/ 文档:htt

  • 问题内容: 它们都使用相同的语法来插入变量。例如,如果我想要以下内容 在我的下划线中,我的主要EJS中断,因为它试图替换用户名,并且主页中不存在此类变量。 问题答案: 我认为方括号默认情况下可以在EJS中使用: 而且,如果您需要更高级的知识,EJS github页面将介绍如何创建自定义标签: 我认为第二个“更高级”部分可能特定于服务器端应用程序 https://github.com/visionm

  • 我是JavaFX的新手,通常也不太熟悉使用Java中的数据库,但是我必须转换我制作的现有JavaFX程序,以删除填充TableView表的列表,并用数据库中的项目替换它,并赋予用户添加或删除的能力。对于学生来说,这基本上是一个非常简化的课程注册程序。一切正常,我只需要使用一个数据库,这样就可以使用教员端来查看哪些学生注册了哪些课程。我只是不熟悉调用数据库并将其应用到tableView的最佳方式。我

  • 问题内容: 给定使用AngularJS 1.2 rc3的测试用例:http : //plnkr.co/edit/MX6otx(以下重复) 1。 2。 问题: 为什么1不起作用? 1个应该工作吗? 为什么2起作用? 2应该工作吗? 我可以依靠2来进行AngularJS的将来更新吗? 问题答案: 为什么1不起作用?: 因为ngIf定义了自己的作用域,它通常是从其父作用域继承的(就像ngRepeat一样

  • 问题内容: 如何创建使芹菜任务看起来像的包装器?还是有更好的方法与Celery集成? Celery的创建者@asksol这样说: 将Celery用作异步I / O框架之上的分布式层是很常见的(提示:将CPU绑定的任务路由到prefork worker意味着它们不会阻塞事件循环)。 但是我找不到任何专门针对框架的代码示例。 问题答案: 如官方网站上所述,这可以通过Celery 5.0版实现: htt