let's assume - regardless from technology and programming languages - you have a type and the type has an association to another type. This association has the complexity of 'at least one' (1..n). How would you specify the behavior, when removing elements from this association based on a predicate? Say, the predicate fits to all elements, thus the removal would violate the 1..n constraint, would you remove all elements but one or would you rather not remove any element in this case (and have a transactional-like behavior)?
That depends on the context:
- If there were a default element (an element that somehow stands out), I would prefer your second suggestion of deleting all but that one element.
If all elements are equal and it makes no sense to define a default element, I would not select an arbitrary one not to delete, because that seems like it could lead to confusing and arbitrary behavior. And an unclean design, because if the predicate makes sense, then why doesn't the multiplicity of the association have (0..n)? I would thus look for a different solution, e.g.
- restrict the predicate to those that don't fit to all elements, if that makes sense in your case
- not remove any element and give the according feedback to the user/client, so that he can change the predicate or pick one element not to delete
- change the association to (0..n).
If the criteria affects all occurrences of the (many) side, you should not proceed with the delete, otherwise, you'd violate the design.
However, there is 1 case where you are allowed (optionally) to delete all occurrences of the (many) side. This is the case when the parent (the one side) is deleted.
Say, you have an association between an invoice header and the invoice items on this invoice, so one invoice contains (1...n) items. If you delete the invoice, all the items have to go. If you attempt to delete the last invoice item, the system should warn you that if you do that, the entire invoice will be deleted.
I would simply not allow removal of all elements. Do not expose such an option in your domain model.
RemoveAllBut(element) method might be acceptable, though it will need to check that the element is indeed in the collection.