Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multirelations #1335

Open
PavelWhiteTiger opened this issue Oct 30, 2024 · 5 comments
Open

Multirelations #1335

PavelWhiteTiger opened this issue Oct 30, 2024 · 5 comments

Comments

@PavelWhiteTiger
Copy link

PavelWhiteTiger commented Oct 30, 2024

When I add a relationship using my client application, this method may duplicate the relationships.
image

@PavelWhiteTiger
Copy link
Author

This example is in the AddReferenceChange class.

@PavelWhiteTiger
Copy link
Author

PavelWhiteTiger commented Oct 30, 2024

Example of creation and using on my app.

IfcRelationship ifcRel = model.getRichModel().create(model.getClient().getMetaDataManager().getPackageMetaData("ifc4x3").getEClass("IfcRelContainedInSpatialStructure"));  <--- Creating rel
        
for (String relPropertyName : relPropertyNames) { // relPropertyNames "RelatingStructure", "RelatedElements"
    EReference eAttribute = model.getClient().getMetaDataManager().getPackageMetaData("ifc4x3").getEReference(relType, relPropertyName);
    eAttributes.add(eAttribute);
}
HashMap<EReference, List<IdEObject>> attributeValuesMap = new HashMap<>();
    for (int i = 0; i < eAttributes.size(); i++) {
        attributeValuesMap.put(eAttributes.get(i), listElements.get(i));
}

        for (EReference eReference : attributeValuesMap.keySet()) {
            List<IdEObject> objList = attributeValuesMap.get(eReference);
            if (eReference.isMany()) {
                List list = (List) ifcRel.eGet(eReference);
                for (Object o : objList) {
                    list.add(o);
                }
            } else if (objList.size() > 0) {
                ifcRel.eSet(eReference, objList.get(0));
            }
}





@hlg
Copy link
Member

hlg commented Oct 30, 2024

In theory, yes. But actually I don't see how, unless you add a reference twice (line 77) - then its inverse will also be added twice (line 92).

EClass eClassForOid = transaction.getDatabaseSession().getEClassForOid(referenceOid);
object.addReference(eReference, eClassForOid, referenceOid);
transaction.updated(object);
EReference inverseOrOpposite = packageMetaData.getInverseOrOpposite(eClassForOid, eReference);
if (inverseOrOpposite != null) {
HashMapVirtualObject referencedObject = transaction.get(referenceOid);
if (referencedObject == null) {
Query query = new Query(packageMetaData);
QueryPart queryPart = query.createQueryPart();
queryPart.addOid(referenceOid);
QueryObjectProvider queryObjectProvider = new QueryObjectProvider(transaction.getDatabaseSession(), transaction.getBimServer(), query, Collections.singleton(transaction.getPreviousRevision().getOid()), packageMetaData);
referencedObject = queryObjectProvider.next();
}
if (inverseOrOpposite.isMany()) {
referencedObject.addReference(inverseOrOpposite, eClassForOid, oid);
} else {
referencedObject.setReference(inverseOrOpposite, oid);
}
transaction.updated(referencedObject);
}

In your example, "RelatingStructure" is a simple feature, but its inverse "IsDecomposedBy" is an aggregate (isMany). We need to add the inverse to any possibly existing inverses. Imagine

Previously, there was a call to fixInverses in the CommitTransactionDatabaseAction, which would recreate all the inverses. This made sense for whole file checkins, but not for lowlevel changes, where it would lead to a gradual accumulation of duplicate inverses with every commit. It was removed in 252850f and that commit made it into 1.5.185. Which version are you using? Do you have that change?

@hlg
Copy link
Member

hlg commented Oct 30, 2024

Thinking about it, we actually have the information wether a particular feature allows for duplicates or not (isUnique). Thus we could, similar to the EMF EList implementation, protect the model and its virtual objects from users violating the model constraints. In fact, at the moment, in IFC all inverses are SETs and as such unique, but this is not set in stone. Imagine, for example a polygon with a list of points that allow for repitition (say equal first and last point) and each point can be used in multiple polygons. Then, the respective inverse feature would be an aggregate that allows for duplication (BAG). Also, it would not be trivial to realize this protection. Currently every ignorant client can just get the list for an aggregate feature and add to that.

I am not absolutely sure, but I think in ClientIfcModel for example, we work with EList which protects from duplication unless the feature allows for it.

@PavelWhiteTiger
Copy link
Author

When I use eGet on client I get specially EList whom knows about rules, but bimserver works another (there is eGet into addReference ), it get simple list without rules. Which version I use I write later...
But fixInverse deleted from commit action.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants