-
1. Re: Find all references to a specific node?
hchiorean Nov 12, 2014 2:20 PM (in response to brmeyer)1 of 1 people found this helpfulJCR has built-in types for REFERENCE (strong) and WEAKREFERENCE (weak). Using hard-references enforces integrity validation.
For example: modeshape/references.cnd at master · ModeShape/modeshape · GitHub
-
2. Re: Re: Find all references to a specific node?
rhauch Nov 12, 2014 2:53 PM (in response to hchiorean)1 of 1 people found this helpfulLike Horia said, JCR's REFERENCE properties (not WEAKREFERENCE or SIMPLEREFERENCE) will prevent removal of referenced nodes. There is nothing to configure, other than registering a custom node type (which can be done programmatically).
As for the JCR-SQL2 queries and references, one option is to find all nodes that refer (via any properties) to a specific set of nodes:
SELECT * FROM [nt:unstructured] WHERE REFERENCE() = $id
where the value of the "$id" variable can be bound to a specific node identifier (e.g., the result of 'node.getIdentifier()'). Of course, you can use a literal string rather than having to use a bind variable. If you want to find nodes that have references to one of a set of nodes, you can use the IN clause, this time using 3 string literals:
SELECT * FROM [nt:unstructured] WHERE REFERENCE() IN ('id1','id2','id3)
The right side of the IN clause can even be a subquery:
SELECT * FROM [nt:unstructured] WHERE REFERENCE() IN (
SELECT referenced.[jcr:uuid] FROM [nt:unstructured] AS referenced WHERE ... )
Note that the REFERENCE clause is specific to ModeShape, but it has multiple forms in case you want to constrain any REFERENCE property (like those above) or a specific REFERENCE via the property's name:
SELECT * FROM [nt:unstructured] AS referring WHERE REFERENCE(referring.[someReferenceProperty]) IN (
SELECT referenced.[jcr:uuid] FROM [nt:unstructured] AS referenced WHERE ... )
Alternatively, you can use a JOIN rather than the REFERENCE clause that specifies a single REFERENCE property. The following query should produce similar results to the previous query, if:
SELECT referring.* FROM [nt:unstructured] AS referring
JOIN [nt:unstructured] AS referred ON referring WHERE referring.[someReferenceProperty] = referred.[jcr:uuid]
WHERE ...
Hope this helps.
-
3. Re: Find all references to a specific node?
brmeyer Nov 12, 2014 3:11 PM (in response to brmeyer)Thanks guys, that's what I originally thought would work as well. However, with the following setup, using strong references, the violations do not occur.
https://gist.github.com/brmeyer/76d9ddbccc0df39a9c95
The only differences I can see:
- The referenceable is a mixin.
- The references use "multiple"
Any other ideas what else we could be missing? Thanks for the help
-
4. Re: Find all references to a specific node?
rhauch Nov 12, 2014 3:20 PM (in response to brmeyer)The only differences I can see:
- The referenceable is a mixin.
- The references use "multiple"
Any other ideas what else we could be missing? Thanks for the help
The 'mix:referenceable' node type is a mixin, so there's no option here. Try removing the 'multiple' to see if that results in constraint violation exceptions when removing the referenced node; but I'd be really surprised if that's changed.
Just to confirm, you have several nodes:
- node A of type 'sramp:baseArtifactType'
- node R of type 'sramp:relationship', with a property 'sramp:relationshipTarget' that contains a reference to node A
If you save this state, then when you try to remove node A and then save those changes, you should get a constraint violation exception. Are you saying that you are able to save the removal of node A even though node R contains a REFERENCE to it?
-
5. Re: Find all references to a specific node?
brmeyer Nov 12, 2014 3:28 PM (in response to brmeyer)Say you have 2 nodes, A & B, both of type sramp:baseArtifactType (ignore the fact that it's abstract). A->relationship->relationshipTarget references B. I'm currently able to delete B with no violation.
Note that both relationship and relationship#relationshipTarget are multiple. Each relationship can have multiple targets, and each artifact can have multiple relationships.
-
6. Re: Find all references to a specific node?
rhauch Nov 12, 2014 3:33 PM (in response to brmeyer)Say you have 2 nodes, A & B, both of type sramp:baseArtifactType (ignore the fact that it's abstract). A->relationship->relationshipTarget references B. I'm currently able to delete B with no violation.
And you're able to save your changes removing node B?
Note that both relationship and relationship#relationshipTarget are multiple. Each relationship can have multiple targets, and each artifact can have multiple relationships.
Like I said, try changing the 'multiple' to be singular and see if this changes the behavior, but this should affect what you're doing.
If nothing else, we'll need a test case that replicates the problem. We have a number of existing test cases that you could follow, or you could just create a new unit test or new test project from scratch.
-
7. Re: Find all references to a specific node?
brmeyer Nov 12, 2014 3:36 PM (in response to rhauch)> And you're able to save your changes removing node B?
Correct. The removal and save results in no exceptions.
> we'll need a test case that replicates the problem
Of course. It'll be nearly impossible to strip "multiple" within S-RAMP itself. However, I'll work on something standalone ASAP.
-
8. Re: Find all references to a specific node?
brmeyer Nov 13, 2014 11:23 AM (in response to brmeyer)So, I'm not the brightest crayon in the box. I completely forgot that S-RAMP doesn't actually delete the node. We move it to a separate "trash" branch of the tree and keep it permanently, for historical and auditing purposes.
Despite my stupidity, Randall, thanks much for the queries. That will be really helpful for rolling our own checks.
-
9. Re: Find all references to a specific node?
rhauch Nov 13, 2014 12:00 PM (in response to brmeyer)No worries, Brett. I'm glad everything is working for you.
-
10. Re: Find all references to a specific node?
brmeyer Nov 13, 2014 1:58 PM (in response to brmeyer)For completeness' sake, in case someone else is looking for a solution:
In our tree, relationships are defined as separate nodes, in order to support 1.) ad-hoc relationships and 2.) relationships carrying additional metadata (relationship type name, etc.). So, the CND includes something like:
[sramp:relationship] - sramp:relationshipType (string) ... (additional properties) - sramp:relationshipTarget (reference) multiple < 'sramp:baseArtifactType' [sramp:baseArtifactType] > mix:referenceable abstract mixin + * (sramp:relationship)
Then, the following query will find all [sramp:relationship]'s that point to the given target.
// This query will find all *relationship* nodes that point *to* the given artifact UUID. In addition, // the ISDESCENDANTNODE call ensures the relationship node is on the root path, *not* in the trash. String query = String.format("SELECT * FROM [sramp:relationship] WHERE " + "ISDESCENDANTNODE([sramp:relationship],'" + JCRConstants.ROOT_PATH + "') AND " + "REFERENCE() IN (SELECT referenced.[jcr:uuid] FROM [sramp:baseArtifactType] AS referenced WHERE referenced.[sramp:uuid] = '%1$s')", uuid);