umldiagramsocl

How to possibly do this in ocl?


I have the following schema: enter image description here

For the Boss class, I need the name of all the agents who made the sales with the highest value (something like: foreach agent, select agent name if he has max(foreach command, total = total + price of the product * quantity from command). How do I do this in OCL?


Solution

  • If you consider that you are at the root of the model (no context in particular) in order to select the 20 first top Agents:

    Agent.allInstances()->sortedBy(- sale->collect(quantity*product.price)->sum())->subSequence(1, 20)
    

    and from a Boss instance:

    self.workers->sortedBy(- sale->collect(quantity*product.price)->sum())->subSequence(1, 20)
    

    The idea behind the request is (for the 1st one):

    1. get all the agents (Agent.allInstances())
    2. sort them (...->sortedBy(...))
    3. using the sum of their sales (... sale->...->sum())
    4. a "sale" is defined by the mult. of the quantity by the price of the referenced product (quantity*product.price)
    5. for each sale, compute this stuff (...sale->collect(...))
    6. from this final result (the sum one), inverse the result to have the top in first positions (... - sale->collect()->sum()...)
    7. from this final list, select a sub sequence (...->subSequence(1,X))

    EDIT>

    Just a detail about association class navigation (from the "OCL Specification", p.21)

    To specify navigation to association classes (Job and Marriage in the example), OCL uses a dot and the name of the association class

    Following the early version of the specification, the Association Class name is said to be put as lower case, in the later version, the name is let untouched.

    EDIT2>

    In order to get the higher score and the agents name who hits this highest score:

    let score : Integer = -(self.workers->collect(sale->collect(quantity*product.price)->sum())->sortedBy(i | -i)->first())
    in self.workers->select(sale->collect(quantity*product.price)->sum() = score).name
    

    The first let select the higher score (collect all the scores, sort them in reverse order and select the first element), then select all the workers who have a score equals to the previously computed one.