gpt4 book ai didi

Java MongoDB 对象版本控制

转载 作者:IT老高 更新时间:2023-10-28 13:10:00 24 4
gpt4 key购买 nike

我需要对存储在面向文档的数据库 (MongoDB) 中的(简单)Java 对象图进行版本控制。对于关系数据库和 Hibernate,我发现了 Envers并对这些可能性感到非常惊讶。是否有类似的东西可以与 Spring Data Documents 一起使用?

我找到了 this post概述我对存储对象版本的想法(以及更多......),并且我当前的实现工作类似,因为它将对象的副本存储在带有时间戳的单独历史集合中,但我想改进它以保存储存空间。因此,我认为我需要在对象树上实现“差异”操作和重构旧对象的“合并”操作。有没有图书馆可以帮助解决这个问题?

编辑:任何使用 MongoDB 和版本控制的经验都非常感谢!我认为很可能不会有 Spring Data 解决方案。

最佳答案

这就是我最终为 MongoDB 实体实现版本控制的方式。感谢 StackOverflow 社区的帮助!

  • 每个实体的更改日志都保存在单独的历史集合中。
  • 为了避免保存大量数据,历史集合不存储完整的实例,而只存储第一个版本和版本之间的差异。 (您甚至可以省略第一个版本,并从实体主集合中的当前版本“向后”重构版本。)
  • Java Object Diff用于生成对象差异。
  • 为了能够正确使用集合,需要实现实体的 equals 方法,以便它测试数据库主键而不是子属性。 (否则,JavaObjectDiff 将无法识别集合元素中的属性更改。)

以下是我用于版本控制的实体(getter/setter 等已删除):

// This entity is stored once (1:1) per entity that is to be versioned
// in an own collection
public class MongoDiffHistoryEntry {
/* history id */
private String id;

/* reference to original entity */
private String objectId;

/* copy of original entity (first version) */
private Object originalObject;

/* differences collection */
private List<MongoDiffHistoryChange> differences;

/* delete flag */
private boolean deleted;
}

// changeset for a single version
public class MongoDiffHistoryChange {
private Date historyDate;
private List<MongoDiffHistoryChangeItem> items;
}

// a single property change
public class MongoDiffHistoryChangeItem {
/* path to changed property (PropertyPath) */
private String path;

/* change state (NEW, CHANGED, REMOVED etc.) */
private Node.State state;

/* original value (empty for NEW) */
private Object base;

/* new value (empty for REMOVED) */
private Object modified;
}

这里是 saveChangeHistory 操作:

private void saveChangeHistory(Object working, Object base) {
assert working != null && base != null;
assert working.getClass().equals(base.getClass());

String baseId = ObjectUtil.getPrimaryKeyValue(base).toString();
String workingId = ObjectUtil.getPrimaryKeyValue(working).toString();
assert baseId != null && workingId != null && baseId.equals(workingId);

MongoDiffHistoryEntry entry = getObjectHistory(base.getClass(), baseId);
if (entry == null) {
//throw new RuntimeException("history not found: " + base.getClass().getName() + "#" + baseId);
logger.warn("history lost - create new base history record: {}#{}", base.getClass().getName(), baseId);
saveNewHistory(base);
saveHistory(working, base);
return;
}

final MongoDiffHistoryChange change = new MongoDiffHistoryChange();
change.setHistoryDate(new Date());
change.setItems(new ArrayList<MongoDiffHistoryChangeItem>());

ObjectDiffer differ = ObjectDifferFactory.getInstance();
Node root = differ.compare(working, base);
root.visit(new MongoDiffHistoryChangeVisitor(change, working, base));

if (entry.getDifferences() == null)
entry.setDifferences(new ArrayList<MongoDiffHistoryChange>());
entry.getDifferences().add(change);

mongoTemplate.save(entry, getHistoryCollectionName(working.getClass()));
}

这是它在 MongoDB 中的样子:

{
"_id" : ObjectId("5040a9e73c75ad7e3590e538"),
"_class" : "MongoDiffHistoryEntry",
"objectId" : "5034c7a83c75c52dddcbd554",
"originalObject" : {
BLABLABLA, including sections collection etc.
},
"differences" : [{
"historyDate" : ISODate("2012-08-31T12:11:19.667Z"),
"items" : [{
"path" : "/sections[LetterSection@116a3de]",
"state" : "ADDED",
"modified" : {
"_class" : "LetterSection",
"_id" : ObjectId("5034c7a83c75c52dddcbd556"),
"letterId" : "5034c7a83c75c52dddcbd554",
"sectionIndex" : 2,
"stringContent" : "BLABLA",
"contentMimetype" : "text/plain",
"sectionConfiguration" : "BLUBB"
}
}, {
"path" : "/sections[LetterSection@19546ee]",
"state" : "REMOVED",
"base" : {
"_class" : "LetterSection",
"_id" : ObjectId("5034c7a83c75c52dddcbd556"),
"letterId" : "5034c7a83c75c52dddcbd554",
"sectionIndex" : 2,
"stringContent" : "BLABLABLA",
"contentMimetype" : "text/plain",
"sectionConfiguration" : "BLUBB"
}
}]
}, {
"historyDate" : ISODate("2012-08-31T13:15:32.574Z"),
"items" : [{
"path" : "/sections[LetterSection@44a38a]/stringContent",
"state" : "CHANGED",
"base" : "blub5",
"modified" : "blub6"
}]
},
}],
"deleted" : false
}

编辑:这是访客代码:

public class MongoDiffHistoryChangeVisitor implements Visitor {

private MongoDiffHistoryChange change;
private Object working;
private Object base;

public MongoDiffHistoryChangeVisitor(MongoDiffHistoryChange change, Object working, Object base) {
this.change = change;
this.working = working;
this.base = base;
}

public void accept(Node node, Visit visit) {
if (node.isRootNode() && !node.hasChanges() ||
node.hasChanges() && node.getChildren().isEmpty()) {
MongoDiffHistoryChangeItem diffItem = new MongoDiffHistoryChangeItem();
diffItem.setPath(node.getPropertyPath().toString());
diffItem.setState(node.getState());

if (node.getState() != State.UNTOUCHED) {
diffItem.setBase(node.canonicalGet(base));
diffItem.setModified(node.canonicalGet(working));
}

if (change.getItems() == null)
change.setItems(new ArrayList<MongoDiffHistoryChangeItem>());
change.getItems().add(diffItem);
}
}

}

关于Java MongoDB 对象版本控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12104969/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com