EMF-как программно удалить экземпляр из модели

Я создал свою метамодель под названием WFG.ecore.

С помощью ATL мне удалось преобразовать файл bpmn2 в модель WFG. Преобразование ATL дает объект WorkFlow, который является контейнером всех других объектов в WFG.

Теперь я хотел бы программно изменить объект WorkFlow на Java, но не могу.

Как я могу удалить экземпляр объекта из его контейнера и так из всех вхождений?

Ниже приведен пример с экземплярами

            gateways
           +--------->+----------+
           |          |Gateway_1 |
           ♦          +----------+
+-----------+              ^
|WorkFlow_1 |              | nextGateway 0..1
+-----------+              |
           ♦           +---------+
           |           | Node_1  |
           +---------->+---------+
           nodes

Я хотел бы удалить экземпляр Gateway_1, чтобы он больше не содержался в WorkFlow_1, и чтобы Node_1.getNextGateway->null. Я пытался сделать WorkFlow_1.getGateways().remove(Gateway_1), но не работает


person DeLac    schedule 28.03.2014    source источник


Ответы (2)


Наивный ответ — использовать команду EcoreUtil.delete() или Delete. Оба они удаляют EObject из его контейнера и удаляют (то есть обнуляют) любые перекрестные ссылки. Однако в целом вы не хотите делать это таким образом по следующим причинам:

  1. Ссылки на детей. Хотя EcoreUtil.delete(Gateway_1) удалит Gateway_1 из своего контейнера и из ссылки Node_1, он не удалит перекрестные ссылки на дочерние элементы Gateway_1, ДАЖЕ ОНИ БУДУТ УДАЛЕНЫ из своего контейнера. . Таким образом, вы можете получить висячие ссылки на несуществующие объекты, которые были дочерними элементами Gateway_1.

  2. Производительность. Не существует надежного способа эффективного поиска перекрестных ссылок. Это означает, что каждый объект EObject в вашей модели будет проверен на наличие перекрестной ссылки на Gateway_1, чтобы перекрестную ссылку можно было удалить. Это делает EcoreUtil.delete() операцией O(n), где n — количество объектов EObject в вашей модели.

Лучшим решением является комбинация двунаправленных ссылок и карт ссылок. Либо Gateway_1 должен знать, кто ссылается на него, либо эта информация должна быть доступна в другом месте. Таким образом, вы можете эффективно и полностью удалить все ссылки на Gateway_1.

Этот ответ тесно связан с этим сообщением в блоге, EMF Dos и Запрещается №11, авторы Максимилиан Кегель и Йонас Хелминг.

Кстати, EcoreUtil.remove() НЕ удаляет перекрестные ссылки, он просто удаляет EObject из его контейнера.

person Erick G. Hagstrom    schedule 28.05.2015
comment
Начиная с версии 2.4, у вас также есть другая версия delete(EObject eObject, boolean recursive): если рекурсивный true, содержащиеся дочерние объекты объекта, которые находятся в том же ресурсе, аналогичным образом удаляются из любых функций, которые на них ссылаются. - person lorenzo-bettini; 04.12.2020
comment
Спасибо за обновление, @lorenzo-bettini - person Erick G. Hagstrom; 15.12.2020

DeleteCommand.create(editingDomain, Collections.singleton(Gateway_1));
editingDomain.getCommandStack().execute(command);

И для Node_1:

Node_1.setNextGateway(null);
person Severin    schedule 28.03.2014
comment
Поэтому мне приходится вручную удалять рекурсивные ссылки, недостаточно просто удалить объект из контейнера. Есть ли способ сделать это автоматически? Ручное удаление ссылок очень подвержено ошибкам, особенно если я буду добавлять новые ссылки в будущем, и трудно не забыть добавить также относительный код удаления. благодарю вас - person DeLac; 28.03.2014
comment
Методы удаления EcoreUtil могут помочь: download.eclipse.org/modeling/emf/emf/javadoc/2.5.0/org/eclipse/ - person Severin; 30.03.2014
comment
DeleteCommand автоматически удаляет перекрестные ссылки. Вам не нужно делать вторую часть, Node_1.setNextGateway(null); - person Erick G. Hagstrom; 28.05.2015