poniedziałek, 8 września 2008

Active Record - Aktywny Rekord

Dziś weźmiemy na warsztat - Active Record, który jest stosunkowo bardzo prostym wzorcem. Chodzi w nim o to, że tworzymy obiekt złożony z danych zawierający zachowanie (metody [w tym biznesowe]).

Przypuśćmy, że mamy do napisania obiekt Active Record - Owoc, który ma zawierać -metody CRUD,
-i jakieś 2 metody biznesowe

Mapujemy sobie tabelę Owoc:



   1:  class Owoc

   2:  {

   3:    // "Dane" owocu

   4:    public int Id { get; set; }

   5:    public int Nazwa { get; set; }

   6:    public decimal Cena { get; set; }

   7:    public decimal Rabat { get; set; }

   8:  }



Dopiszmy metody CRUD na samym początku:



   1:  class Owoc

   2:  {

   3:    public Owoc() {}

   4:    

   5:    public Owoc(int id)

   6:    {

   7:      Owoc o = Find(id);

   8:      this.Id = o.Id;

   9:      this.Nazwa = o.Nazwa;

  10:      this.Cena = o.Cena;

  11:      this.Rabat = o.Rabat;

  12:    }

  13:   

  14:    public static Find(int id)

  15:    {

  16:      Owoc o = // Wyciagniecie owocu z bazy i zmapowanie go

  17:      return o;

  18:    }

  19:   

  20:    public Owoc Save()

  21:    {

  22:      // Zapis

  23:    }

  24:    

  25:    public void Update()

  26:    {

  27:      // Update

  28:    } 

  29:    

  30:    public void Delete()

  31:    {

  32:      // Usunięcie

  33:    }

  34:  }



Tutaj trzeba zwrócić uwagę na metodę Find, która musi być statyczna.
Jeśliby nie była, to nie moglibyśmy w stanie jej użyć do konstrukcji obiektu.

Rzućmy okiem na użycie Rekordu Aktywnego:


   1:  // Wyciagamy owoc o id 4

   2:  Owoc o = new Owoc(4);

   3:  Owoc o = Owoc.Find(4);

   4:   

   5:  // Zapisujemy nowy owoc do bazy

   6:  Owoc o = new Owoc() { Nazwa = "jablko", Cena = 20, Rabat = 50 };

   7:  o.Save();

   8:   

   9:  // Updatujemy dane owocu

  10:  o.Nazwa = "Gruszka";

  11:  o.Update();

  12:   

  13:  // Usuwamy go

  14:  o.Delete();



Bardzo wygodne, prawda? ;)

Teraz podepnijmy getter biznesowy obliczający cenę jabłka z rabatem:


   1:  class Jablko

   2:  {

   3:    // ...

   4:    public decimal CenaZrabatem

   5:    {

   6:      get

   7:      {

   8:        return cena - rabat;

   9:      }

  10:    }

  11:  }



No to jak nam tak dobrze idzie, to dopiszmy kolejny getter biznesowy
określający czy jabłko jest na promocji:


   1:  class Jablko

   2:  {

   3:    // ...

   4:    public bool CzyNaPromocji

   5:    {

   6:      get

   7:      {

   8:        return rabat > 0;

   9:      }

  10:    }

  11:  }



Szybki przykład użycia (trochę bezsensowny, no ale trzeba z obrazować problem ;) ):



   1:  decimal cenaOwocu = 0;

   2:   

   3:  Owoc jablko = new Owoc(5);

   4:   

   5:  cenaOwocu = jablko.Cena;

   6:   

   7:  if ( jablko.CzyNaPromocji )

   8:  {

   9:    cenaOwocu = jablko.CenaZrabatem;

  10:  }



No i git, wszystko ładnie i pięknie... czy aby do końca jest to prawda?
Jak to zwyklę bywa... nie.
-Active Record nie powinniśmy stosować gdy mamy do czynienia ze złozoną logiką
biznesową
-AC wiąże się z konkretną bazą (np. CRUD zawiera SQL dla konkretnej bazy, nie jesteśmy go w stanie podmienić)

Niby tylko dwa minusy, ale za to jakie ;)

2 komentarze:

Anonimowy pisze...

Great post! Keep going man! Kiedy bedzie druga czesc postu o integracji SVN z Visual Studio? Chetnie poznalbym blizej ten program.

Laziers pisze...

dzięki,
pamiętam Twój poprzedni komentarz, właśnie o SVNie przewiduje w przyszłym tygodniu w sobotę bądź niedziele, trochę trzeba poczekać lecz na prawdę nie dam rady inaczej.