Pokazywanie postów oznaczonych etykietą System Płacowy. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą System Płacowy. Pokaż wszystkie posty

sobota, 6 września 2008

II System płacowy (cz. 3) - Model dziedziny (Mapowanie)

Skoro mamy już warstwę dostępu do danych, to przyszedł czas na zrobienie modelu dziedziny.

Najpierw musimy się zastanowić jakie tabele w bazie będziemy mieli hmm

1. Zawód - będą przechowywane tutaj nazwy zawodów
2. Pracownik - jak się nie trudno domyśleć będą tutaj pracownicy
3. Przepracowane godziny- ilość przepracowanych godzin

To chyba tyle (przynajmniej na teraz).

Bierzmy się zatem do stworzenie modelu dziedziny.

A tak w ogóle to co to jest ten cały model? Można skrócić wywód ;) i zapisać go w jednym zdaniu: Model dziedziny są to obiekty, które modelują jakąś dziedzinę (wow odkrycie ;)). U nas będą to po prostu zmapowane (jeden do jednego) tabele.

Okey skoro już wiemy co to jest, zatem przejdźmy do akcji. Ale pierwsze... czas na obiad ;)

[po 30 min. przerwy obiadowej nasz zespół pełny (jedzenia ;)) zapału wkracza do pokoju by kontynuować pracę]


Na czym to skończyliśmy hmm... coś tam poudawaliśmy, pogadaliśmy sobie potem była przerwa... a tak! mapowanie tabel :)

Użyjemy sposobu mapowania: Foreign Key Mapping

Ale zaraz na razie nie mamy czego mapować, musimy utworzyć tabele:

zawod
id : int,
nazwa : varchar

pracownik
id : int,
imie : varchar
zawod_id : int

przepracowane_godziny
id : int,
pracownik_id : int
ilosc_godzin : int
data : dateTime

Mapnijmy to ;)

Zawód:
public class Zawod
{
public int Id { get; set; }
public string Nazwa { get; set; }

public Zawod(int id, string nazwa)
{
this.id = id;
this.Nazwa = nazwa;
}
}


Pracownik:
public class Pracownik
{
public int Id { get; set; }
public string Imie { get; set; }
public int ZawodId { get; set; }

public Pracownik (int id, string imie, int zawodId)
{
this.Id = id;
this.Imie = imie;
this.ZawodId = zawodId;
}
}


Przepracowane godziny:
public class PrzepracowaneGodziny
{
public int Id { get; set; }
public int PracownikId { get; set; }
public int IloscGodzin { get; set; }
public DateTime Data { get; set; }

public PrzepracowaneGodziny(int id, int pracownikId, int iloscGodzin, DateTime data)
{
this.Id = id;
this.PracownikId = pracownikId;
this.IloscGodzin = iloscGodzin;
this.Data = data;
}
}


Job done...

piątek, 1 sierpnia 2008

I SystemPlacowy.DataAccessLayer (cz. 2)

[Ja zamiast tworzyć w Visual Studio Express wole pisać w SharpDevelop 3.0. Ma wbudowane narzędzia do testów, pokrycia kodu etc., lecz niestety brakuje mu paru rzeczy z VS, no ale to zawsze jakaś miła alternatywa ;)]

Dość gadania, bierzemy się za stworzenie warstwy dostępu do danych.
Projekty:



Z racji tego, że wszystko robimy w TDD (test driven development) zaczynamy od utworzenia testu połączenia z bazą.

[Test]
public void TestConnection()
{

}


Świetnie już prawie gotowe! To tyle ... żartowałem oczywiście ;)

Wiemy że dostęp będzie się odbywać przez klasę DataAccess. Skoro to wszystko musi być elastyczne, czyli DataAccess nie może być uzależniony od konkretnej bazy danych musimy stworzyć interface IDataProvider. Każdy dostawca danych będzie implementował ten interface:

public interface IDataProvider
{
IDbConnection Connection { get; }
}


Okey, rozszerzmy nasz test o dodatkową metodę:

[SetUp]
public void SetUp()
{
dataAccess = new DataAccess();
}


Atrybut [SetUp] uruchamia metodę JEDEN RAZ PRZED TESTEM.


Świetnie, lecz czegoś nam tu brakuje. Pasowałoby jakoś przekazać do DataAccess konkretnego providera. Może po prostu go wstrzykniemy przez konstruktor :)?

[SetUp]
public void SetUp()
{
dataAccess = new DataAccess(new MySqlDataProvider());
}


Kompilujemy projekt i proszę, niespodzianka! Nie chce się nam projekt kompilować. Brakuje tej klasy. Niezwłocznie stwórzmy ją w katalogu SystemPlacowy.DataAccessLayer.DataProvider:


public class MySqlDataProvider : IDataProvider
{
public MySqlDataProvider()
{
}

public IDbConnection Connection
{
get
{
return new MySqlConnection();
}
}
}


Teraz uruchamiamy test:


SharpDevelop 3.0

Zgodnie z oczekiwaniami test kończy się niepowodzeniem, ciekawe dlaczego ;) Lecimy do klasy MySqlDataProvider, po czym dopisujemy w getterze otwarcie połączenia.

public IDbConnection Connection
{
get
{
try
{
IDbConnection connection = new MySqlConnection(connectionString);
connection.Open();

return connection;
}
catch (MySqlException ex)
{
Console.WriteLine(ex.Message + " " + ex.StackTrace);

return new MySqlConnection();
}
}
}


Teraz test przechodzi :)



Podobnie robimy tak ze wszystkimi metodami jakie będziemy potrzebować (wszystko znajdziecie w kodzie źródłowym w 3 częsci).

Do tej pory wszystko mamy dobrze popisane, lecz dochodzimy do wniosku, że każde użycie DataAccess wiąże się z utworzeniem obiektu i wstrzyknięciem do niego MySqlDataProvider. Już to sobie wyobrażamy, że w każdymi miejscu w DAO tworzymy taki obiekt, bleeee. Na pomoc przychodzi nam (nieustraszony) Ninject, (podobnie jak Autofac jest kontenerem IoC).



Tworzymy klasę SystemPlacowy.DataAccessLayer.DataAccessModule : StandardModule. Przeciążamy metodę Load() i w jej ciele definiujemy moduł:

public class DataAccessModule : StandardModule
{
public override void Load()
{
Bind<DataAccess>().ToSelf();
Bind<IDataProvider>().To<MySqlDataProvider>();
}
}


W skrócie można to co się znajduje w Load() przetłumaczyć jako: wszędzie tam gdzie spotkasz IDataProvider to zastąp go MySqlDataProvider. Dzięki zastosowaniu takiego rozwiązania, w każdej chwili możemy sobie zmienić w tym JEDNYM I JEDYNYM miejscu w projekcie z MySqlDataProvider na inny np MsSqlDataProvider.

Zmieńmy nasz test:
[TestFixture]
public class TestDataAccess
{
private IKernel kernel;

[SetUp]
public void SetUp()
{
kernel = new StandardKernel(new DataAccessModule());
}

[Test]
public void TestConnection()
{
Assert.IsTrue(kernel.Get<DataAccess>().Connection.State == ConnectionState.Open);
}
}

Jest okey :) Yeah! Dobra robota... Nigdzie nawet nie użyliśmy "new" przy tworzeniu DataAccess, czy można chcieć od życia czegoś więcej? ;)

cdn...

środa, 23 lipca 2008

TDD. Przykładowa aplikacja cz. 5 / System płacowy cz. 1

Hmm klient się do nas wciąż nie odzywa. W sumie to i dobrze, bo ciągle robimy sobie wakacje ale dość tego! Czas się zająć refaktoryzacją naszej aplikacji. Podczas trwania urlopu na obozie programistycznym (jasne ;)), dowiedzieliśmy się o istnieniu całkiem ciekawych projektów: Autofac oraz PostSharp. Tak bardzo nas zainteresowały, że postanowiliśmy je wdrożyć do całej aplikacji. Ba! co tam chodźmy za ciosem, przebudujemy całą i DAJMY JEJ W KOŃCU JAKĄŚ nazwę ;)!.. póki klient milczy. Zacznijmy więc od początku.

Podzielmy naszą aplikację na warstwy.

I. Warstwa dostępu do danych. Tutaj stworzymy mechanizm odpowiedzialny za dostęp/komunikację z bazą, zupełnie elastyczny, niezależny od rodzaju bazy.

II. Domain Model (Model dziedziny). Zmapowane tabele bazy danych, DAO, reguły biznesowe.

III. Services (Serwisy). Ta warstwa będzie udostępniać funkcje aplikacji (coś na kształt uporządkowanego API systemu).

IV. Interface Klienta. Czyli po prostu w skrócie... formatki ;)


Cały model będzie tak wyglądać:



Nie noo.. wszystko super, zobaczymy jak to wyjdzie w praktyce.

Strukturę już mamy, wiemy co mamy robić, toteż przyszedł czas na nadanie nazwy dla programu... może po prostu... System Płacowy...? Mało oryginalny :| lecz nasz zlasowany mózg po urlopie na razie nie jest w stanie wymyśleć czegoś chwytliwego ;)

Bierzmy się do roboty.

Ściągamy projekty:
-NAnt
-NHibernate (później nam się przyda)
-NUnit
-NMock
-Ninject
-PostSharp

Na pierwszy rzut idzie I warstwa, dostęp do danych.

cdn.