Graphql 工具:将实体类型映射到 graphql 类型

Posted

技术标签:

【中文标题】Graphql 工具:将实体类型映射到 graphql 类型【英文标题】:Graphql Tools: Map entity type to graphql type 【发布时间】:2020-03-07 03:11:06 【问题描述】:

我在我的 spring 应用程序中使用了 graphql java 工具。我有一个这样的实体:

@Entity
data class Image(
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        @Column(nullable = false)
        val id: Long = 0
) 
    @Lob
    @Column(nullable = false)
    var image: Blob? = null

而在 GraphQL 架构中,我想要一个不同的类型:

type Image 
    id: ID!
    image: String!
   

当然,由于架构解析异常,启动它是行不通的。 所以我认为必须有可能在模式解析之间放置一些东西来实现从BlobString的映射。

这里有可能吗?

@Bean
fun schemaParserDictionary(): SchemaParserDictionary 
    return SchemaParserDictionary()

编辑

抱歉,它不会给出架构解析异常。它只会将字节放入字符串中。但是我不能使用那个字符串来创建图像。

澄清

抱歉,我想我的问题不够清楚。我不需要知道如何将 blob 转换为字符串。有非常简单的解决方案。例如,我可以使用一个简单的 API 函数将字节码转换为 base64:

val base64 = Base64.getEncoder().encodeToString(byteCode)

我想问的是如何“告诉”graphql 模式解析器为特定字段使用“自定义”转换。因此,当我的实体对象具有数据类型为blob 的字段image 时,graphql 会自动将其转换为string。但字符串不包含我需要的内容。所以我想为那个特定的字段使用自定义解析/映射/转换/任何东西。当然,我也可以通过引入另一个我不存储在数据库中的字段来轻松解决这个问题:

@Entity
data class Image(
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        @Column(nullable = false)
        val id: Long = 0
) 
    @Lob
    @Column(nullable = false)
    var image: Blob? = null

    @Transient
    var base64: String = ""

但我可以通过 graphql api 进行查询:

type Image 
    id: ID!
    image: String!
    base64: String!


type Images 
    images: [Image!]!
    totalCount: Int!


type Query 
    getImages: Images!

并将其设置在我的控制器中:

private fun getImages(): Images 
    var images: List<Image> = repository.findTop1000()

    images.forEach 
        it.base64 = Base64.getEncoder().encodeToString(it.image)

        queue.offer(it)
    


但如果我可以告诉 graphql 模式解析器这样做会更简洁。

【问题讨论】:

【参考方案1】:

为什么不使用自定义标量?它直接回答了您的起始问题:

所以我认为必须有可能在两者之间放置一些东西 架构解析以实现从 Blob 到 String 的映射。

这里有可能吗?

您的 GraphQL 架构将是:

scalar ImageBlob
type Image 
    id: ID!
    image: ImageBlob!
 

然后,在自定义标量实现中,您提供 Blob 从字符串到字符串的转换。

【讨论】:

【参考方案2】:

Kushal 的回答提供了将 Blob 转换为字符串的 sn-ps。要使用此转换,最好使用 DTO。

为此,请将您的 graphql 架构转换为:

type ImageDTO 
    id: ID!
    image: String!
 

并创建一个DTO类ImageDTO:

public class ImageDTO 
    private Image entity;

    //Constructor
    public ImageDTO(Image image) 
         this.entity=image;
    

    //Getters
    public Long getId() 
        return entity.getId();
    

    public String getImage() 
        //convert the entity image and return it as String
        return Base64.getEncoder().encodeToString(entity.getImage());
    

将 DTO 与实体分开可以让您更好地控制传输的数据。

【讨论】:

您好,感谢您的回复。我想我的问题不够清楚,对此感到抱歉。我更新了我原来的帖子。 @Mulgard 我认为我的回答符合您的需要。您的实体对象包含一个 Blob 图像,并且您想要传输一个字符串。您需要使用数据传输对象 (DTO) 来执行此操作。将您的 graphql 类型直接映射到您的实体不是一个好习惯,因为它不会让您控制您传输的数据或强制您更新模型以匹配您的外部 api。我更新了 ImageDTO.getImage() 方法,这样你就可以看到我在哪里做 Blob 和 String 之间的映射。 schemaParserDictionnary 只允许您根据需要将 graphql 类型与 java 类型进行映射。我认为您无法映射特定字段。【参考方案3】:

让我们从头开始检查。我们知道 BLOB 是 Binary Large Object 的首字母缩写词,用于存储超过特定数据类型允许的常规大小的字节和字节数据。如果 BLOB 数据太大,将 BLOB 转换为内存中的字符串有时会导致 OutOfMemoryException

但是,如果您想将 BLOB 转换为字符串,您可以尝试以下代码:

String s = "";
InputStream inStream = b.getBinaryStream();
//b is your BLOB
InputStreamReader inStreamReader = new InputStreamReader(inStream);
BufferedReader reader = new BufferedReader(inStreamReader );
StringBuffer buf = new StringBuffer();
while(s = reader.readLine())

   buf.append(s);

您还可以采取其他几种方法,其中一种是

ByteArrayOutputStream baos = new ByteAttayOutputStream();
byte[] buf = new byte[1024];
InputStream in = blob.getBinaryStream();
int n = 0;
while ((n=in.read(buf))>=0)

   baos.write(buf, 0, n);

in.close();
byte[] bytes = baos.toByteArray();
String blobString = new String(bytes); 

如果您有任何进一步的疑问,我将不胜感激。

【讨论】:

您好,感谢您的回复。我想我的问题不够清楚,对此感到抱歉。我更新了我原来的帖子。

以上是关于Graphql 工具:将实体类型映射到 graphql 类型的主要内容,如果未能解决你的问题,请参考以下文章

使用graphql代码生成器时如何将自定义标量类型映射到打字稿类型?

如何将 graphQL 查询属性映射到不同的响应属性?

GraphQL 到 PostgresQL 类型映射

REST 映射到 GraphQL

实体框架 - 您能否将导入的存储过程的结果类型映射到自定义实体类型?

如何更新 graphql 端点(不使用 Graph.cool)