Encje
Zacznijmy od tworzenia encji. Na potrzeby budowania architektury aplikacji narazie stworze tylko 1 encje. Będzie nią użytkownik. Zacznijmy od zaimplementowania interfejsu encji. Częścią wspólna każdej encji jest id. Więc nasz interfejs będzie posiadał właśnie to pole.
public interface IEntity { Guid Id { get; set; } }Aby ułatwić sobie sprawę stworzymy bazowa encje która będzie implementowała powyższy interfejs. Spowoduje to ze nie będziemy musieć w każdej encji wypisywać pola id. W razie gdyby pojawiły się inne pola które będą wspólne równie łatwo będzie można modyfikowac bazowa encje co spowoduje zmiany w wszystkich encjach.
Oto implementacja bazowej encji:
public abstract class BaseEntity : IEntity { public virtual Guid Id { get; set; } }
Jak juz mamy podstawowe typy z których będą dziedziczyły nasze encje możemy teraz zaimplementować pierwsza z nich:
public class User : BaseEntity, IEntity { public virtual string Username { get; set; } public virtual string Password { get; set; } public virtual string Email { get; set; } public virtual string PasswordQuestion { get; set; } public virtual string PasswordAnswer { get; set; } public virtual bool isLockedOut { get; set; } public virtual DateTime LastActivityDate { get; set; } public virtual DateTime LastLoginDate { get; set; } public virtual DateTime LastLockedOutDate { get; set; } public virtual DateTime CreatedDate { get; set; } }
Repozytoria
Następnie chciałbym co nieco powiedzieć na temat obiektów które będzie można znaleźć w moim projekcie. Są to repozytoria. Repozytorium jest to klasa która bezpośrednio ma dostęp do bazy danych. Udostępnia on podstawowe operacje CRUD jak i inne bezpośrednio związane z dana encja. Pośredniczy miedzy baza a usługami które te dane będą potrzebowały. Pozwala to na uniezależniane projektu od konkretnego ORM-a. Podmiana wymaga jedynie zaimplementowania kontekstu bazy danych oraz poszczególnych repozytoriów. Implementacja interfejsu repozytorium wygląda tak:
public interface IRepository<TEntity> where TEntity : class { TEntity GetById(Guid id); IEnumerable<TEntity> GetBySpec(ISpecification<TEntity> spec); void Add(TEntity entity); void Delete(Guid id); void Delete(TEntity entity); IEnumerable<TEntity> GetPagedElements<S>(int pageIndex, int pageSize, Expression<Func<TEntity, S>> orderExpression, bool ascending); IEnumerable<TEntity> GetPagedElements<S>(int pageIndex, int pageSize, Expression<Func<TEntity, S>> orderExpression, ISpecification<TEntity> specification, bool ascending); IEnumerable<TEntity> All(); }Większość funkcji tutaj jest raczej zrozumiała. Jedyna zagadka możne być ISpecifcation interfejs. Spójrzmy na przykładowa implementacje:
public class UserOnlineUsersSpecification : Specification<User> { private DateTime _onlineTime; public UserOnlineUsersSpecification() { } public override Expression<Func<User, bool>> SatisfiedBy() { _onlineTime = DateTime.Now.AddMinutes(-5); return x => x.LastActivityDate >= _onlineTime; } }Ta specyfikacja ma za zadanie zwrócić wyrażenie lamba które pozwoli nam znaleźć aktualnie użytkowników online. Jak widzymy kazda specyfikacja sklada sie metody SatisfiedBy która zwraca wyrażenie lamba. To wyrażenie jest wykorzystywane w bazie do pobrania odpowiednich danych. Krótko mówiac jest to mała cześć logiki biznesowej opakowana w klase co powoduje że może byc używana w wielu miejscach i unikamy powtórzeń w kodzie. Wiecej na temat tego wzorca mozna znaleść na Wikipedi
W nastepnych wpisach zajmiemy sie juz konkretna implementacja klas zwiazanych z NHibernate i baza danych.
Brak komentarzy:
Prześlij komentarz