2

Imagine an ORM system, independent of language but let's assume PHP. Data is encapsulated in PHP objects and stored into and loaded from database.

Let us have a theoretical object "Person" with multiple addresses (so mapped to 2 tables in database), which can be added by a function.

Do NOT consider how access on data elements is done, it does not matter.

Some sample code:

$person = new Person();

$person->firstname = 'John';
$person->lastname  = 'Doe';
// ...

// THIS IS IMPORTANT!
$person->save();

$person->addAddress([
    'street' => '123, Foo Street',
    'city'   => 'New York',
    // ...
]);

$person->addAddress([
    'street' => '456, Bla Street',
    'city'   => 'Washington',
    // ...
]);

What would you expect about how (when!) the addresses are saved?

Option 1: They are immediately saved after the call to addAddress()

Option 2: The call to addAddress() does only put it into the internal object, and they get saved only after an explit call to Person::save().

Option 3: Any further ideas are welcome.

I want to know which most people would prefer, which is more intuitive, if there are pros/cons for/against the different options. Maybe a killing argument?

Moreover, I suppose that Option 2 is harder to code (I know, using some framework can handle this, but assume that the database-object-mapping is much more complicate, so it must be done by hand), because it needs internal tracking of new entries, removed entries, changed entries etc.

Option 1 is easier to code, but I do not know if users (even if they are just in our company) will misunderstand this.

  • Note : for hibernate it's Option 3. You call persist() when you need to insert but update are either done if you call merge() explicitly, or on commit if you modified entities. Which means for insert you have a fail fast behaviour while on update, if you don't call merge, you will have a fail on commit, which is triciker to debug, but avoid unnecassry multiple update when the task rely on multiple subsystems that each modify a part of the entitiy. However with hibernate, it's not the person that has the save method but the entity Manager. – Walfrat Mar 22 '17 at 10:27
  • Why is Person responsible for its persistence in the database? Wouldn't this be better handled by a separate object? See en.wikipedia.org/wiki/Single_responsibility_principle – Radu Murzea Mar 22 '17 at 13:45
  • @RaduMurzea Some others argue that having an object that have data and nothing else is an anti-pattern called "anemic pattern". An object could perfectly know where he store himself, though this is not usually how we do. See stackoverflow.com/questions/1399027/… . For a rich object that know how to store hiself, I would recommande though that the object handling the transaction/Session is externalized and passed to the save method. – Walfrat Mar 22 '17 at 14:20
  • FWIW, I usually go with approach #2. – GrandmasterB Mar 22 '17 at 17:30
1

Never mix data handling with transaction handling. Doing so makes your data handling methods not reusable. Let the caller commits the database, this will let your the caller of your data modifying method to compose multiple calls to run in a single transaction, and if anything goes wrong, to rollback them all transactionally.

So I'd suggest doing Option 2.

The only other improvements I'd suggest is that rather than

$person->save();

instead have an explicit database session:

// either: $session->add($person);
// or: $person = new Person($session);
// alternatively: $person = $session.create(Person);

$session->save();

Explicit sessions might seem cumbersome initially, but a lot of other things easier that you'll later appreciate. Testing becomes easier, reusing methods becomes easier, multiple databases becomes possible, etc.

0

[Option 3]

Maybe you should take a look at Entity and Repository patterns, it could help you to figure it out. For example:

Your have your Person entity

<?php
namespace PersonEntity\subnamespace;
class PersonEntity {
    public $firstname;
    public $lastname;

static function register(){}

}
?>

Create an Interface for your Entity

<?php
interface PersonRepository {
   public function save(Person $person);
}
?>

Then you just need to create a class that implements your interface

<?php    
class ArrayPersonRepository implements PersonRepository {
      public function save(Person $person){}
}
?>

Then you can interact with your Repository, like this way:

$person = PersonEntity::register($firstname, $lastname)
$personRepository->save($person)

The advantages to code using this patterns are:

  • Keep it SOLID.
  • Change your database to whatever you desire.
  • Code is testable easily.

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.