Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Active Records vs. Repository - pros and cons?

Using ActiveRecord you might define a class like this:

class Contact
{
  private String _name;
  public String Name
  {
    get { return _name; }
    set 
    { 
      if (value == String.IsNullOrWhiteSpace())
        throw new ArgumentException(...);
      else
        _name = value;
    }
  }

  public Boolean Validate() { ... /* check Name is unique in DB */  }

  public Boolean Save() { ... }

  public static List<Contact> Load() { ... }
}

Whilst this is nice and simple, I've found my classes become very bloated with a big mix of logic going on!

Using a layered/domain design you might define the same class like:

class Contact
{
    [Required(AllowEmptyStrings=false)]
    public String Name { get; set; }
}

class ContactService : IService
{
    public List<Contact> LoadContacts() { return (new ContactRepository()).GetAll(); }
    public Contact LoadContact(int id) { return (new ContactRepository()).GetById(id); }
    public Boolean SaveContact(Contact contact)
    {
        if (new ContactValidator().Validate(contact))
            new ContactRepository().Save(contact);
    }
}

class ContactRepository : IRepository
{
    public List<Contact> GetAll() { ... }
    public Contact GetById(int Id) { ... }
    public Boolean Save(Contact contact) { ... }
}

class ContactValidator : IValidator
{
    public Boolean Validate(Contact contact) { ... /* check Name is unique in DB */ }
}

class UnitOfWork : IUnitOfWork
{
    IRepository _contacts = null;
    public UnitOfWork(IRepository contacts) { _contacts = contacts; }
    public Commit() { _contacts.Save(); }
}

How was it migrated from Active Record => layered design?

  • Entity level validation in the Name setter => remains (ableit via a DataAnnotation)
  • Business logic/rule validation (unique Name) => moved from entity into a new separate ContactValidator
  • Save logic => moved to a separate Repository pattern class (also with a UnitOfWork)
  • Load logic => moved to the separate Repository
  • Interaction with the Repository is via a new ContactService (which will enforce use of ContactValidator, ContactRepository, UnitOfWork, etc - opposed to letting the caller loose with the ContactRepository!).

I'm looking for peer approval/suggestions for this layered design - I don't usually design outside of Active Record type! Any comment appreciated.

NB - This example is deliberately simple (the UnitOfWork isn't really used and the newing of Repository/Validator would be handled differently).

like image 965
Matt Avatar asked Jun 29 '11 14:06

Matt


People also ask

Why not to use Active Record?

The biggest drawback to active record is that your domain usually becomes tightly coupled to a particular persistence mechanism. Should that mechanism require a global change, perhaps from file-based to DB-based persistence, or between data access frameworks, EVERY class that implements this pattern may change.

Is repository pattern as same as Active Record pattern?

They are different. Active Record Pattern defines An object that wraps a row in a database table or view, encapsulates the data access, and adds domain logic on that data. In the Repository pattern all of the data access is put in a separate class and is accessed via instance methods.

What is the purpose of active records?

Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database. It is an implementation of the Active Record pattern which itself is a description of an Object Relational Mapping system.

What is Active Record in TypeORM?

What is the Active Record pattern? In TypeORM you can use both the Active Record and the Data Mapper patterns. Using the Active Record approach, you define all your query methods inside the model itself, and you save, remove, and load objects using model methods.


3 Answers

It really depends on how complex your domain logic is. For example if I was writing a simple blog then active record will be fine, mostly the application is saving and loading data. Its simple and active record pattern is the right tool for the job.

However if I was writing software for a shipping company in which there are many complex business rules and processes then using the repository pattern, along with other Domain Driven Design patterns will provide at much more maintainable code in the long run.

Using domain driven design you would use the specification pattern to achieve your validation.

like image 154
g.foley Avatar answered Sep 20 '22 18:09

g.foley


This article seems like a good and succinct description of both: https://hashnode.com/post/which-design-pattern-do-you-prefer-active-record-or-repository-cilozoaa5016o6t53mhsdu6nu

One thing I would like to add is it isn't just "active record is good when your persistence needs are simple and repository is good when your persistence needs are complex". The choice of pattern here has a lot more to do with how you feel about the Law of Demeter. If you want different parts of your architecture to be completely separated so that someone can understand one part without understanding another then you want the Law of Demeter. That said I think, especially early on in a project when the spec is likely to change, it is VERY dangerous to get too obsessive about these sorts of abstraction. Don't second guess your project's future maintainers, they might be smart and they should be able to think about more than one thing at a time and if they can't then you might have larger problems that cannot be prevented by using the Repository pattern.

like image 39
olleicua Avatar answered Sep 22 '22 18:09

olleicua


Both approaches has their pros and cons.

Pretend, you're passing Active Record-styled object to somewhere (deep inside BL). You can read it, you can changed it, you can SAVE it. In this case, that piece of BL is only coupled with you entity's interface. With layered architecture you then have to somehow pass repository to that code. You'd either pass it explicitly or use IoC-container - up to you.

The other point is that when you have the concept of repository, you can easily define concepts like we-have-a-new-object-in-repository, or one-object-has-been-deleted-from-repository which are basically quite useful notifications if you're working with distributed environment.

like image 28
Andrey Agibalov Avatar answered Sep 20 '22 18:09

Andrey Agibalov