3

In most MVC web projects there is a User class. Many times a user has something else in a one-to-many relationship, i.e. orders.

If we have a user class that has many orders, should methods that add, edit or delete orders for a user be placed in the user class, or in a separate Order class?

i.e.

1.

user.add_order(order_name)   //Instance method

vs

2.

Order.add_order_for_user(user_id, order_name)   //Static method

or alternatively,

3.

order = new Order(user_id,order_name)
order.save()

(Also, in the case of option 3, should this be combined with option 1 and put in that method)?

My main issue with option 1 is that the user model tends to get huge in terms of size. Does this violate SRP? For instance, in one of my projects a user has many "things" like friended users, feeds, uploaded files, warnings, punishments, and the list goes on. I'm basically adding CRUD methods for all those "things" that a particular user has many of, in the User class itself. Is this a bad thing, and should I spread out the CRUD methods to different classes?

However, one of the advantages for option 1 is that I can control logic in those CRUD methods using the attributes of the current user object, without having to query the user. For instance, if I have a method "add_file" I can check to see if the user's total file space used (an attribute of User) is less than a max without having do do another query.

1

Generally all nouns should have their own class, a model in the case of using the mvc pattern. User and order are two separate things so you should have two models. However, they are related so your data model should have a key or bridge table to relate users with orders. A user has orders but a user is not updated from an order but more precisely an order record is updated, so you'd want to use the order model for your crud operations.

The problem with scenario 1 is that your code will be tightly coupled to a user.

Also, looks like you should be passing in the order id and user id, not the order name to maintain good practices using proper constraints.

1

If your case is order processing which is focusing in orders, then I believe Order is the root aggregate entity that has a reference to User entity, for example:

class Order {

   User user   

   Payment payment

   Delivery delivery

   ...
}

If you want to select Order based on User, you can create new methods in your repository such as:

interface OrderRepository {

   public List<Order> findOrderByUser(User user); 

   public List<Order> findOrderByUserAndStatus(User user, OrderStatus status);

}

If you have business logic that requires some calculations in User based on Order, you can add required Order to User. Usually it is not all Order that has been created by that user (your concern is they are too many to store in User, right?). For example, it can be pendingOrder:

class User {

    List<PendingOrder> pendingOrders = []

    BigDecimal creditLimit

    boolean allowNewOrder() {
       ...  // check if sum of pendingOrders is not more than allowed limit
    }
}

I believe this will make your domain classes richer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.