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...

Brak komentarzy: