ORM: Data Mapper vs. Active Record

Dec 06 2022
Welches ist besser und warum?
ORM steht für Object-Relational Mapping, also die Technik, die Objekte aus OOP in Zeilen in der Datenbank umwandelt und umgekehrt. Es gibt zwei Muster: Aktiver Datensatz Wie bereits erwähnt, kann die Entität selbst erstellt, aktualisiert oder gelöscht werden.

ORM steht für Object-Relational Mapping , also die Technik, die Objekte aus OOP in Zeilen in der Datenbank umwandelt und umgekehrt.

Es gibt zwei Muster:

  • Aktiver Datensatz : Der Datensatz (Entität) selbst kann die DB aktiv ändern
  • Data Mapper : Es gibt ein externes Objekt, das die Entitäten beibehält

Aktiver Rekord

Wie bereits erwähnt, kann die Entität selbst erstellt, aktualisiert oder gelöscht werden. In PHP zum Beispiel ist Eloquent ein Active Record ORM, das von der Laravel-Community entwickelt wurde.

final class UserCreator
{
    public function create(UserInformation $userInfo): void
    {
        $address = Address::createFrom($userInfo->address());
        $address->save() # Address is stored in the database

        $user = User::createFrom($userInfo->user());
        $user->address = $address; // Set relationship
        $user->save(); # User is stored in the database
    }
}

Im Data Mapper benötigen wir eine externe Klasse, die die DB aktualisiert. In PHP zum Beispiel ist Doctrine de facto das Data Mapper ORM für Symfony.

final class UserCreator
{
    public function __construct(
        private EntityManager $entityManager,
    ) {}

    public function create(UserInformation $userInfo): void
    {
        $address = Address::createFrom($userInfo->address());
        $user = User::createFrom($userInfo->user());
        $user->address = $address; # Set relationship

        # We persist all objects we want to update
        $this->entityManager->persist($address);
        $this->entityManager->persist($user);

        # Finally, flushing the entity manager will execute the SQLs
        $this->entityManager->flush();
    }
}

Wenn Sie sich beide Snippets ansehen, können Sie jedoch bereits sehen, dass der Data Mapper eine externe Abhängigkeit ( Entity ManagerObjekt) verwendet, die seltsam und eindeutig schwieriger ist, wenn Sie sich entscheiden, einige Tests in die Klasse einzuführen UserCreator, inzwischen in der Active RecordKlasse, die Entitäten speichern sich selbst, also haben wir auf einen Blick keine Abhängigkeit, aber das stimmt nicht ganz, die Entität selbst hat Kenntnis von der DB, und es wird schwierig sein, einige Tests zu schreiben, wenn wir die Entität direkt verwenden User.

Repository-Muster

Das Repository-Muster ist ein Entwurfsmuster, das die Datenbanklogik in einer neuen Klasse verbirgt und nur die Methoden bereitstellt, die wir dem Benutzer bereitstellen möchten.

Dazu müssen wir eine Schnittstelle und eine Klasse erstellen, die die Schnittstelle implementiert, in der wir die gesamte Logik löschen.

# App/User/Domain
interface UserRepository
{
    public function save(UserInformation $userInfo): void;
}

~~~~

# App/User/Infrastructure
final class ActiveRecordUserRepository implements UserRepository
{
    public function save(UserInformation $userInfo): void
    {
        $address = Address::createFrom($userInfo->address());
        $address->save()

        $user = User::createFrom($userInfo->user());
        $user->address = $address;
        $user->save();
    }
}

final class DataMapperUserRepository implements UserRepository
{
    public function __construct(
        private EntityManager $entityManager,
    ) {}

    public function create(UserInformation $userInfo): void
    {
        $address = Address::createFrom($userInfo->address());
        $user = User::createFrom($userInfo->user());
        $user->address = $address;

        $this->entityManager->persist($address);
        $this->entityManager->persist($user);
        $this->entityManager->flush();
    }
}

final class UserCreator
{
    public function __construct(
        private UserRepository $userRepository,
    ) {}

    public function create(UserInformation $userInfo): void
    {
        $this->userRepository->save($userInfo);
    }
}