避免保存嵌套对象的空属性 - Amazon SDK for Java 2.x
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

避免保存嵌套对象的空属性

在将数据类对象保存到 DynamoDB 时,您可以通过应用 @DynamoDbIgnoreNulls 注释来跳过嵌套对象的空属性。相比之下,具有空值的顶级属性永远不会保存到数据库中。

为了说明该注释的工作原理,代码示例使用了以下两个 Bean。

以下数据类包含两个 InnerBean 字段。getter 方法 getInnerBeanWithoutAnno() 不使用注释。getInnerBeanWithIgnoreNullsAnno() 方法使用注释 @DynamoDbIgnoreNulls

@DynamoDbBean public class MyBean { private String id; private String name; private InnerBean innerBeanWithoutAnno; private InnerBean innerBeanWithIgnoreNullsAnno; @DynamoDbPartitionKey public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public InnerBean getInnerBeanWithoutAnno() { return innerBeanWithoutAnno; } public void setInnerBeanWithoutAnno(InnerBean innerBeanWithoutAnno) { this.innerBeanWithoutAnno = innerBeanWithoutAnno; } @DynamoDbIgnoreNulls public InnerBean getInnerBeanWithIgnoreNullsAnno() { return innerBeanWithIgnoreNullsAnno; } public void setInnerBeanWithIgnoreNullsAnno(InnerBean innerBeanWithAnno) { this.innerBeanWithIgnoreNullsAnno = innerBeanWithAnno; } @Override public String toString() { return new StringJoiner(", ", MyBean.class.getSimpleName() + "[", "]") .add("innerBeanWithoutAnno=" + innerBeanWithoutAnno) .add("innerBeanWithIgnoreNullsAnno=" + innerBeanWithIgnoreNullsAnno) .add("id='" + id + "'") .add("name='" + name + "'") .toString(); } }

以下 InnerBean 类的实例是 MyBean 的字段,用于以下示例代码。

@DynamoDbBean public class InnerBean { private String innerBeanFieldString; private Integer innerBeanFieldInteger; public String getInnerBeanFieldString() { return innerBeanFieldString; } public void setInnerBeanFieldString(String innerBeanFieldString) { this.innerBeanFieldString = innerBeanFieldString; } public Integer getInnerBeanFieldInteger() { return innerBeanFieldInteger; } public void setInnerBeanFieldInteger(Integer innerBeanFieldInteger) { this.innerBeanFieldInteger = innerBeanFieldInteger; } @Override public String toString() { return new StringJoiner(", ", InnerBean.class.getSimpleName() + "[", "]") .add("innerBeanFieldString='" + innerBeanFieldString + "'") .add("innerBeanFieldInteger=" + innerBeanFieldInteger) .toString(); } }

以下代码示例创建一个 InnerBean 对象,并仅为其两个属性中的一个设置了值。

public void ignoreNullsAnnoUsingPutItemExample(DynamoDbTable<MyBean> myBeanTable) { // Create an InnerBean object and give only one attribute a value. InnerBean innerBeanOneAttributeSet = new InnerBean(); innerBeanOneAttributeSet.setInnerBeanFieldInteger(200); // Create a MyBean instance and use the same InnerBean instance both for attributes. MyBean bean = new MyBean(); bean.setId("1"); bean.setInnerBeanWithoutAnno(innerBeanOneAttributeSet); bean.setInnerBeanWithIgnoreNullsAnno(innerBeanOneAttributeSet); Map<String, AttributeValue> itemMap = myBeanTable.tableSchema().itemToMap(bean, true); logger.info(itemMap.toString()); // Log the map that is sent to the database. // {innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)}), id=AttributeValue(S=1), innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})} // Save the MyBean object to the table. myBeanTable.putItem(bean); }

为了可视化发送到 DynamoDB 的低级别数据,该代码会在保存 MyBean 对象之前记录属性映射。

记录的输出显示,innerBeanWithIgnoreNullsAnno 输出了一个属性,

innerBeanWithIgnoreNullsAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200)})

innerBeanWithoutAnno 实例输出了两个属性。一个属性的值为 200,另一个属性的值为空。

innerBeanWithoutAnno=AttributeValue(M={innerBeanFieldInteger=AttributeValue(N=200), innerBeanFieldString=AttributeValue(NUL=true)})

以下 JSON 表示可以更轻松地查看保存到 DynamoDB 的数据。

{ "id": { "S": "1" }, "innerBeanWithIgnoreNullsAnno": { "M": { "innerBeanFieldInteger": { "N": "200" } } }, "innerBeanWithoutAnno": { "M": { "innerBeanFieldInteger": { "N": "200" }, "innerBeanFieldString": { "NULL": true } } } }

您可以使用以下 StaticTableSchema 版本的表架构来代替数据类标注。

public static TableSchema<MyBean> buildStaticSchemas() { StaticTableSchema<InnerBean> innerBeanStaticTableSchema = StaticTableSchema.builder(InnerBean.class) .newItemSupplier(InnerBean::new) .addAttribute(String.class, a -> a.name("innerBeanFieldString") .getter(InnerBean::getInnerBeanFieldString) .setter(InnerBean::setInnerBeanFieldString)) .addAttribute(Integer.class, a -> a.name("innerBeanFieldInteger") .getter(InnerBean::getInnerBeanFieldInteger) .setter(InnerBean::setInnerBeanFieldInteger)) .build(); return StaticTableSchema.builder(MyBean.class) .newItemSupplier(MyBean::new) .addAttribute(String.class, a -> a.name("id") .getter(MyBean::getId) .setter(MyBean::setId) .addTag(primaryPartitionKey())) .addAttribute(String.class, a -> a.name("name") .getter(MyBean::getName) .setter(MyBean::setName)) .addAttribute(EnhancedType.documentOf(InnerBean.class, innerBeanStaticTableSchema), a -> a.name("innerBeanWithoutAnno") .getter(MyBean::getInnerBeanWithoutAnno) .setter(MyBean::setInnerBeanWithoutAnno)) .addAttribute(EnhancedType.documentOf(InnerBean.class, innerBeanStaticTableSchema, b -> b.ignoreNulls(true)), a -> a.name("innerBeanWithIgnoreNullsAnno") .getter(MyBean::getInnerBeanWithIgnoreNullsAnno) .setter(MyBean::setInnerBeanWithIgnoreNullsAnno)) .build(); }