Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Active Record vs. Repository pattern

12.38 - 21. května 2008 | ASP.NET 2.0

Dnes se podíváme na dva návrhové vzory z oblasti přístupu k datům, které používají zcela odlišnou filosofii, ale nakonec si ukážeme, že jejich kombinací, můžeme získat celkem zajímavé výsledky.

Active Record

Návrhový vzor Active Record staví na předpokladu, že základem aplikace je databázový model a od něj se vše odvíjí. Každý řádek tabulky je reprezentován konkrétní instancí objektu. Většinou je takový objekt odvozen od bázové třídy, která implementuje potřebné rozhranní pro persistenci objektu – typicky CRUD metody.

Diagram vzoru ActiveRecord

Tento vzor se hojně využívá v různých ORM frameworcích. Je součástí dnes velmi módních frameworků Ruby on Rails, django nebo Castle, které na něm stavějí svůj datový model a díky velice snadnému mapování dokážete napsat (vygenerovat) kostru databázové aplikace během několika málo minut.

Pro velice jednoduché aplikace může být tento vzor, díky své jednoduchosti, vhodný. Jenže porušuje několik pravidel dobrého objektového návrhu (persistence ignorance, single responsibility, pevně daná bázová třída, atd.).

Repository

Návrhový vzor Repository je základním kamenem doménou řízeného návrhu. Model aplikace nemá ponětí o tom, jakým způsobem je persistován. O to se stará právě Repository. Navíc díky tomu, že se o persistenci stará cizí objekt, stačí nám znát pouze jeho rozhranní a v případě potřeby ho snadno nahradit jiným.

Diagram vzoru Repository

Kombinace

Teď zabrousím do konkrétnějších implementací a to do ActiveRecord z projektu Castle. Tako konkrétní implementace je postavená na běhovém prostření dotnet a jako svůj základ používá ORM nástroj NHibernate.

Nejpřímější cesta jak s ním pracovat, je podědit třídu z bázové třídy ActiveRecordBase a označit ji a její vlastnosti patřičnými atributy:

[ActiveRecord]
public class User : ActiveRecordBase<User> {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  [Property] public string Email { get; set; }
  [Property] public string Login { get; set; }
  [Property] public string Password { get; set; }
}

A můžeme pracovat. Autoři si však byli vědomi toho, že vzor Active Record nemusí vyhovovat všem a přidali statickou třídu ActiveRecordMediator, který dokáže posloužit jako základ pro Repository. Třída pak nemusí dědit z ActiveRecordBase:

[ActiveRecord]
public class User {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  [Property] public string Email { get; set; }
  [Property] public string Login { get; set; }
  [Property] public string Password { get; set; }
}

public class UsersRepository : IRepository<User> {
  public User Load(int id) {
    return ActiveRecordMediator<User>.FindByPrimaryKey(id);
  }
  public void Save(User obj) {
    ActiveRecordMediator<User>.Save(obj);
  }
  public void Delete(User  obj) {
    ActiveRecordMediator<User>.Delete(obj);
  }
}

To už je o něco lepší, ale stále máme v aplikačním modelu silnou vazbu na datový model. Můžeme se posunout o level dál a zkombinovat oba vzory tak, abychom z nich vytěžili co nejvíce. Základní myšlenkou je to, že v aplikaci budeme mít jak datový model, tak doménový. Datový model se bude pomocí Active Record starat o persistenci a Repository poslouží k transformaci doménového modelu na ten datový.

Něco podobného můžete najít v seriálu, který píše Rob Conery, kde používá zjednodušenou Repository, IQueryable jako filtry a LINQ2SQL jako datový model. Velice zajímavé, doporučuji ke shlédnutí.

Tagy: , ,

Komentáře RSS

  1.  

    Miro

    00.05 - 3. června 2008 | #

    Ahoj, presne takéto niečo hľadám. Nepáči sa mi ale, že nad User máš [ActiveRecord]. Čo keby sme to urobili takto:

    public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string Login { get; set; } public string Password { get; set; } }

    [ActiveRecord] public class ActiveRecordUser : User { [PrimaryKey] public int Id { get; set; } [Property] public string Name { get; set; } [Property] public string Email { get; set; } [Property] public string Login { get; set; } [Property] public string Password { get; set; } }

    Ide mi o to, aby v rámci Persistence Ignorance bol User class „čistý“ a assembly, ktorý ho obsahuje by bol nezávislý od Castle.Active­record.dll

  2.  

    Aleš Roubíček

    06.47 - 3. června 2008 | #

    Díky za komentář. To tvé by myslím nefungovalo. User by to vlastnosti musel mít virtuální nebo být pouze rozhranní. Určité řešení tohoto jsem naznačil v části „kombinace“, kde doménové objekty nejsou označeny ActiveRecord atributy, ale existují jejich DAO protějšky (a nemusí být nutně 1:1) a Repository provádí mapování mezi nimi.

  3.  

    T

    12.01 - 19. března 2009 | #

    Suhlasim s poslednym commentom Ales… ta informacia o NUTNOSTI mappingu vo vztahu ku cistemu DDD v zavere clanku chybala. Ak pouzijes na urovni data acessu active record (pattern) proste inu moznost, ako robit mapping medzi domain entitami a active record objektami nemas.

    To, co v clanku(na zaciatku) popisujes nema s DDD nic spolocneho. Prosto – je to active record pattern. Entity nie su Domenove Entity, ale len nejake behavior less nosice informacii(DTO) medzi DAL a GUI. Persistance ignorance je dalsi problem. Repositories maju nezabezpecovat transofrmaciu medzi domain layerom a db data acess layerom, lebo nie su oddelene, domain layer neexistuje. Takze by si hento ani ako repository nemal nazyvat. (Jedine ak tam pridas tie mappre a budes mat naozaj domenovy model._ Potom Tvoje repositories nebudu nic viac, ako genericke data acess componenty…riesia totiz presne to, co ma pri DDD riesit data acess layer…CRUD. A tiez absentuje rozmer aggregate rootov…to je dalsia vec v ktorej svetle treba vidiet zmysel repositories. Neviem, ci som to vysvetlil zrozumitelne :-(

    A tiez neviem, kam by si umiestnil pri tomto designe business logiku. Ak nad tieto „repositories“ mas vrstvu transactional scriptov. Ak by si ju napchal do tych kvazy „repositories“, tak sa touto vrstvou stanu „repositories“.

    Navyse pouzivanie generic repositories aj pri DDD → paci sa mi tento Gregov nazor

    http://codebet­ter.com/…osito­ry.aspx

Místo pro tvůj názor

Povinné je jméno a komentář, z e-mailu se rozpoznají Gravatary.
Komentář je formátován pomocí Texy! syntaxu.
Například: **tučný text**, *kurzíva*, "text odkazu":adresa.
Internetové adresy jsou převáděny na odkazy.
Na komentáře se můžete odkazovat pomocí [číslo komentáře].

Nový komentář