Как создать отношения «многие ко многим» с помощью Objectify в Google App Engine?

Я не могу найти никакой документации о подходящем способе создания отношений «многие ко многим» между объектами с помощью Objectify в Google App Engine.

Кто-нибудь может объяснить, как это сделать? Нужно ли для этого создавать новый класс «join»? Насколько это будет эффективно?


person sanity    schedule 05.02.2012    source источник


Ответы (4)


Какие типы запросов вам необходимо поддерживать?

Самое простое решение:

@Entity
public class StoredObject {
    @Id
    private Long id;

    private List<Long> relatedIds;
}

затем, учитывая StoredObject, вы можете вызвать objectify.get(StoredObject.class, storedObject.getRelatedIds()), чтобы получить все связанные идентификаторы.

Чтобы ускорить некоторые запросы в моем собственном приложении, я создал несколько классов соединения. Расходы возникают во время записи (вы должны поддерживать соединения), но тогда время чтения — это одно сканирование индекса с последовательными результатами!

person Riley Lark    schedule 05.02.2012
comment
Можете ли вы уточнить, как вы реализовали свои классы соединения? Меня беспокоит эффективность, если у меня есть тысячи элементов в списке relatedIds, особенно если мне нужно получить все объекты, на которые указывают relatedIds одновременно (что может быть обычным для меня) - person sanity; 06.02.2012

Это не лучший подход для сопоставления отношений многие ко многим в Objectify. Лучший способ — создать сущность, отображающую отношения. Например, предположим, что у вас есть два объекта A и B, и они определенным образом связаны. Вы можете создать класс, похожий на:

Class Link{
    Key<?> master;
    key<?> slave;

    public Link(){

    }

    public setLink(Entity master, Entity slave){
     //initialize

    }

}

Затем вы можете создать объект Link для моделирования отношений. Это автоматически сопоставляет отношения «один к одному» или «многие ко многим».

person Gang Su    schedule 15.05.2012

Я решил использовать этот подход с Objectify 4.0:

@Entity
@Index
public class Module {

@Id
private Long id;
private String name;

@Load
private List<Ref<Template>> templates;


public List<Template> getTemplates() {
    List<Template> templates = new ArrayList<Template>();

    for (Ref<Template> temp : this.templates) {
        templates.add(temp.get());
    }

    return templates;
}

public void setTemplates(List<Template> templatesParm) {
    List<Ref<Template>> templates = new ArrayList<Ref<Template>>();

    for (Template temp : templatesParm) {
        templates.add(Ref.create(temp));
    }

    this.templates = templates;

}
person Alejandro    schedule 21.02.2013
comment
Поскольку в объектизации нет такого запроса, как мы можем получить один шаблон, связанный с несколькими модулями? - person Hardik Patel; 27.10.2017

Давайте на мгновение задумаемся об одном-многих; если вы хотите, чтобы объект A «имел много» объектов B, есть только два способа сделать это:

  • Реляционный способ: сделайте так, чтобы каждый B указывал на A. Когда у вас есть A0 и вам нужны все B, которые относятся к нему, просто запросите B, которые указывают на данный A0.

  • Способ NoSQL/ObjectStore: сделайте так, чтобы у A было поле, содержащее список указателей (ключей) на B-s. Обратите внимание, что этот способ также позволяет B-s быть в определенном порядке (несмотря на документы GAE/Java об обратном).

Какой из них лучше, зависит. Способ ObjectStore ограничен размером объекта. Реляционный способ связан с тонкой проблемой, заключающейся в том, что если A и все B не находятся в одной и той же группе сущностей, и вы выполняете запрос предка в транзакции (или, может быть, даже если это не в транзакции), вы гарантированно получите все из B, которые указывают на этот A. Однако, если A и B охватывают группы сущностей, возможно (хотя и маловероятно), что вы получите B, который не удовлетворяет предикату запроса, или пропустите букву Б, которая делает: https://developers.google.com/appengine/articles/transaction_isolation

В (теперь стандартном) хранилище данных с высоким уровнем репликации транзакция обычно полностью применяется в течение нескольких сотен миллисекунд после возврата фиксации. Однако, даже если он не применяется полностью, последующие запросы чтения, записи и предков всегда будут отражать результаты фиксации, поскольку эти операции перед выполнением применяют любые незавершенные изменения. Однако запросы, охватывающие несколько групп сущностей, не могут определить, есть ли какие-либо незавершенные изменения перед выполнением, и могут возвращать устаревшие или частично примененные результаты.

Теперь о многих-многих: однажды я прочитал историю, в которой описывалось посещение туалета в космосе; было четыре комбинации: внутри/снаружи космического корабля и два вида посещения туалета. Для последней комбинации пребывания вне корабля (в скафандре) и устранения твердых тел единственным ответом было «изящного пути не существует» (также название статьи): http://поселение.arc.nasa.gov/CoEvolutionBook/SPACE.HTML#Там Нет Изящного Путь ... и это также ответ на многие-многие отношения в GAE. Вы можете создать их с помощью класса соединения, и каждая сторона соединения может быть реализована с помощью запроса или списка ключей.

person Daniel    schedule 19.05.2012