Skip to content

Commit

Permalink
ReferenceException when trying to persist a reference list with dupli…
Browse files Browse the repository at this point in the history
…cated entries

fixes #2013
  • Loading branch information
evanchooly committed Sep 14, 2022
1 parent c19caaa commit aefcd17
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
Expand All @@ -28,9 +29,9 @@
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class CollectionReference<C extends Collection> extends MorphiaReference<C> {
private final Map<String, List<Object>> collections = new HashMap<>();
private EntityModel entityModel;
private List ids;
private final Map<String, List<Object>> collections = new HashMap<>();

CollectionReference(Datastore datastore, EntityModel entityModel, List ids) {
super(datastore);
Expand All @@ -47,11 +48,6 @@ public abstract class CollectionReference<C extends Collection> extends MorphiaR
}
}

abstract void setValues(List ids);

protected CollectionReference() {
}

static void collate(EntityModel valueType, Map<String, List<Object>> collections,
Object o) {
final String collectionName;
Expand All @@ -72,18 +68,16 @@ static List register(Map<String, List<Object>> collections, String name) {
return collections.computeIfAbsent(name, k -> new ArrayList<>());
}

protected CollectionReference() {
}

/**
* Gets the referenced entities. This may require at least one request to the server.
*
* @return the referenced entities
*/
public abstract C get();

@Override
public Class<C> getType() {
return (Class<C>) entityModel.getType();
}

@Override
public List<Object> getIds() {
List<Object> ids = new ArrayList<>(this.ids);
Expand All @@ -96,6 +90,11 @@ public List<Object> getIds() {
return ids;
}

@Override
public Class<C> getType() {
return (Class<C>) entityModel.getType();
}

@Override
final List<Object> getId(Mapper mapper, Datastore datastore, EntityModel entityModel) {
if (ids == null) {
Expand All @@ -106,6 +105,10 @@ final List<Object> getId(Mapper mapper, Datastore datastore, EntityModel entityM
return ids;
}

abstract Collection<?> getValues();

abstract void setValues(List ids);

private List<Object> extractIds(List<Object> list) {
List<Object> ids = new ArrayList<>();
list.forEach(i -> {
Expand Down Expand Up @@ -149,8 +152,6 @@ final List find() {
return values;
}

abstract Collection<?> getValues();

Map<Object, Object> query(String collection, List<Object> collectionIds) {

final Map<Object, Object> idMap = new HashMap<>();
Expand All @@ -162,7 +163,7 @@ Map<Object, Object> query(String collection, List<Object> collectionIds) {
idMap.put(getDatastore().getMapper().getId(entity), entity);
}

if (!ignoreMissing() && idMap.size() != collectionIds.size()) {
if (!ignoreMissing() && idMap.size() != new HashSet<>(collectionIds).size()) {
throw new ReferenceException(
Sofia.missingReferencedEntities(entityModel.getType().getSimpleName()));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
package dev.morphia.test.mapping.lazy;

import dev.morphia.Datastore;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Reference;
import dev.morphia.test.mapping.ProxyTestBase;
import dev.morphia.test.models.TestEntity;
import org.bson.types.ObjectId;
import org.testng.annotations.Test;

import java.util.List;
import java.util.Objects;

import static dev.morphia.query.experimental.filters.Filters.eq;
import static org.testng.Assert.assertEquals;

@Test(groups = "references")
public class TestLazyIdOnlyIgnoreMissing extends ProxyTestBase {
@Test
public void testDuplicatesInList() {
getMapper().map(ListReferences.class, ReferencedEntity.class);
ListReferences references = new ListReferences();
ReferencedEntity entity1 = new ReferencedEntity();
entity1.foo = "1";
ReferencedEntity entity2 = new ReferencedEntity();
entity2.foo = "2";
getDs().save(List.of(entity1, entity2));
references.list = List.of(entity1, entity2, entity1);
getDs().save(references);

ListReferences first = getDs().find(ListReferences.class).first();

assertEquals(first, references);
}

public void testSaveAfterReferentIsGone() {
checkForProxyTypes();

Expand Down Expand Up @@ -47,6 +70,38 @@ public void testSaveAfterReferentIsGone() {
datastore.save(root);
}

@Entity
private static class ListReferences {
@Id
private ObjectId id;
@Reference
List<ReferencedEntity> list;

private ListReferences() {
}

private ListReferences(List<ReferencedEntity> list) {
this.list = list;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ListReferences)) {
return false;
}
ListReferences that = (ListReferences) o;
return Objects.equals(list, that.list) && Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return Objects.hash(list, id);
}
}

public static class ReferencedEntity extends TestEntity {
private String foo;

Expand All @@ -57,6 +112,24 @@ public String getFoo() {
public void setFoo(String string) {
foo = string;
}

@Override
public int hashCode() {
return Objects.hash(id, foo);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ReferencedEntity)) {
return false;
}
ReferencedEntity that = (ReferencedEntity) o;
return Objects.equals(id, that.id)
&& Objects.equals(foo, that.foo);
}
}

public static class RootEntity extends TestEntity {
Expand Down

0 comments on commit aefcd17

Please sign in to comment.