Java 使SpringData仅更新POJO的已更改字段

Java 使SpringData仅更新POJO的已更改字段,java,spring,mongodb,spring-data,spring-data-mongodb,Java,Spring,Mongodb,Spring Data,Spring Data Mongodb,我在MongoDB上使用Spring数据。我可以保存Pojo,更新它们。很好用。但现在我只想刷新POJO的db更改字段 例如,我有一个用户实体。我创建用户,然后不时更新lastActiveDate @Document class User { @Id BigInteger ID; String email; String name; Date lastActiveDate; } User user = new User(); user.setNam

我在MongoDB上使用Spring数据。我可以保存Pojo,更新它们。很好用。但现在我只想刷新POJO的db更改字段

例如,我有一个用户实体。我创建用户,然后不时更新lastActiveDate

@Document
class User {
    @Id
    BigInteger ID;

    String email;

    String name;

    Date lastActiveDate;
}

User user = new User();
user.setName("User");
user.setEmail("example@example.com");
repository.save(user);

User toUpdUser = repository.findOne(userId);
toUpdUser.setLastActiveDate(new Date);
repository.save(toUpdUser );
在第二次保存中,我希望只更新lastActiveDate字段,而不是整个用户,因为大型实体上的文档更新可能会很慢。我还想知道变更集(至少更新了一组字段)

现在我还没有找到API来做这件事。唯一的可能是在setters中手动处理它(存储一组已更改的字段并手动存储),但它看起来丑陋且不受支持。另一种选择是在bean上使用AOP来实现相同的结果,但IFAIK Spring数据不将POJO视为Spring bean,而是使用构造函数,所以在用AOP加载POJO之后,POJO将只是POJO

UPD: 我正在寻找没有显式mongo api(或类似mongo的api)调用的方法。我有几十个字段的实体,客户几乎可以更改其中的任何一个。我只想存储更改过的字段,并且能够获取变更集来执行一些检查。实体存储和字段更新之间的差异太大-5ms与0.2ms

当然,我可以使用CRUD跟踪器支持创建自己的POJO映射器实现,但它已经存在,为什么不试试呢。我可以使用另一个框架,而不仅仅是SpringData。

您正在寻找的


请参见此处的相关答案:

要更新对象上的各个字段,请使用
更新
API,如中所述。使用
MongoTemplate
可以将其合并到一个存储库中,使用这里描述的机制来实现单个查询方法。

Spring数据不支持逐字段比较,以确定哪些字段被更新,而只将这些字段发送到数据库。虽然它只支持持久化非空字段,但我发现自己在实现
PATCH
PUT
web服务时利用了这一点。创建一个带有非空字段的
$set
对象,您将保持文档的其他部分完好无损

您需要使用
MongoConverters
的一个未记录的功能,下面是
spring mvc
中的
补丁
-webservice的一个示例,它还可以在文档的“events”数组中维护事件的历史记录:

@RestController
公共类MyWebservice{
@自动连线
私人MongoConverter MongoConverter;
@RequestMapping(value=“/order/{id}”,method=PATCH,products=APPLICATION\u JSON\u UTF8\u value,consumes=APPLICATION\u JSON\u UTF8\u value)
public Order updateOrder(@PathVariable(“id”)字符串id,@RequestBody Order)引发JsonProcessingException{
order.setId(id);
DBObject update=getDbObject(顺序);
mongoTemplate.updateFirst(查询(其中(“id”).is(id)),Update.fromDBObject(新的BasicDBObject(“$set”,Update)).push(“事件”,顺序),order.class);
返回mongoTemplate.findOne(查询(其中(“id”).is(id)),Order.class);
}
私有DBObject getDbObject(对象o){
BasicDBObject BasicDBObject=新的BasicDBObject();
mongoConverter.write(o,基本对象);
返回基本对象;
}
}

MongoConverter
只将非空值写入
BasicDBObject

您可以使用Jackson API确定更改的内容并持久化POJO。下面是代码

public class TestJacksonUpdate {

class Person implements Serializable {
    private static final long serialVersionUID = -7207591780123645266L;
    public String code = "1000";
    public String firstNm = "John";
    public String lastNm;
    public Integer age;
    public String comments = "Old Comments";

    @Override
    public String toString() {
        return "Person [code=" + code + ", firstNm=" + firstNm + ", lastNm=" + lastNm + ", age=" + age
                + ", comments=" + comments + "]";
    }
}

public static void main(String[] args) throws JsonProcessingException, IOException {
    TestJacksonUpdate o = new TestJacksonUpdate();

    String input = "{\"code\":\"10000\",\"lastNm\":\"Smith\",\"comments\":\"Jackson Update WOW\"}";
    Person persist = o.new Person();

    System.out.println("persist: " + persist);

    ObjectMapper mapper = new ObjectMapper();
    Person finalPerson = mapper.readerForUpdating(persist).readValue(input);

    System.out.println("Final: " + finalPerson);
    // repository.save(finalPerson);    } }

谢谢,但我正在寻找没有显式MongoAPI调用的方法。我有几十个字段的实体,客户几乎可以更改其中的任何一个。我只想存储更改过的字段,并且能够获取变更集来执行一些检查。实体存储和字段更新之间的差异太大了-5毫秒比0.2毫秒。@AINLOCAT我认为您无法避免显式调用mongo api-祝您好运,如果您发现了什么,请告诉我们。我知道如何手动更新字段。我甚至为性能测试编写了简单的CRUD跟踪器,它可以更新文档中任何深度的任何字段。但我必须在每个集合操作中调用它来记录更改。真烦人。我只是想这样做。当然,若框架不能以这种方式工作,我将实现查询生成、普通CRUD跟踪器、编写AOP以使外部客户满意。我在找像你这样的人也许想重新考虑一下反对票。仅仅因为你不喜欢这个答案,并不意味着它是错误的。我基本上是在说明@gogstad的答案更详细地描述了什么,但建议将其封装到存储库方法中。这很有趣。不是我期望的,但很有趣。我在业务层工作,通常从DB(完整实体)加载实体,如果需要修改它们并存储它们。我可以尝试在加载时和存储前编写convert对象,并对它们进行比较,但它看起来非常难看。