General ORM Design Question

Suppose you have 2 classes: Man and Rabbit. A person can do several things to a rabbit; he / she can either feed him, buy and become his owner, or give him away. A rabbit can have no more than one or no more than 1 owner at a time. And if he is not served for a while, he may die.

Class Person { Void Feed(Rabbit r); Void Buy(Rabbit r); Void Giveaway(Person p, Rabbit r); Rabbit[] rabbits; } Class Rabbit { Bool IsAlive(); Person pwner; } 

There are several observations from the domain model:

  • Face and Rabbit may have links to each other
  • Any actions on 1 object can also change the state of another object
  • Even if no explicit actions are called, there may still be a state change in the objects (for example, Rabbit can starve to death, and this forces him to be removed from the Person.rabbits array)

As a DDD, I believe that the right approach is to synchronize all calls that can change states in the domain model. For example, if a person buys a rabbit, he will need to purchase a castle in the face in order to make changes to the array of rabbits. And another castle in Rabbit to change ownership before releasing the first. This will prevent a race condition in which 2 people claim to own a small rabbit.

Another approach is to allow the database to handle all of these synchronizations. Who makes the first win of the call, but then the database should have some kind of business logic to find out if it is a valid transaction (for example, if the rabbit already has an owner, he cannot change his owner, unless the Person gives it away )

Both approaches have both pros / cons, and Id expects the “best” solution to be somewhere in between. How would you do this in real life? What do you take and worry about?

In addition, is it really important that another race condition may occur that the domain model has made, but before it is fully committed to the database?

And for the third observation (i.e., a change in state due to a time factor). How do you do this?

+4
source share
2 answers

Here are a couple of questions that should help you come up with a design:

  • In fact, should a rabbit know who its owner is? So, is this link needed? If you are trying to model a domain, it is probably unlikely that the rabbit knows who owns it (and what if it separates two people)?
  • Should a person have a link to a rabbit directly? Or do you think it makes sense to have a more general interface like Animal? It seems that these operations are not dependent on the rabbit?
  • As for streaming and synchronization, is your application multithreaded? Is it possible in your application for two people to try to simultaneously become the owner of a rabbit? For example, if you were modeling a pet store, this would not be possible for this (also if the rabbit has no reference to its owner, this problem may not exist anymore).
  • If both objects really need references to each other, I would probably perform synchronization at the object level (using locks). Since you can update the domain model in memory and then save it in the database (perhaps when you disconnect the application or something in this case, if it is a desktop application), you always want the memory to be in a consistent state.
  • In general, start with the simplest solution and refactoring as needed. Given your question and where you are in development, I find it unlikely that a difference in synchronization at the object level or in the database is likely to be a performance issue.
+1
source

1, it may or may not be practical for a rabbit to know its owner, in certain conditions animals know their owners by tags or microchip .... in DDD you model what makes sense in the context of your specific domain, but everything is fine so that they know about each other. You will want to make locks to transfer ownership. It is relatively simple with most ORMs.

third. Does the Owner Own a Dead Rabbit? But its quite simple, as part of the killing of a rabbit, you remove it from its owner. As for what kills the rabbit, perhaps you need a GrimReaper class that is scheduled in a timely manner to see all ILivingThings and works if living conditions are maintained, if not ILivingThing.Slaughter (). Reap ();

+1
source

Source: https://habr.com/ru/post/1308851/


All Articles