Czym konkretnie jest agregat w DDD

0
//Na początku chce uciąć dyskusję dlaczego nie korzystam od razu z ORM'a a tak archaicznie podchodze do wspolpracy z baza danych.
Porównując, żeby nauczyć się jezdzic na rowerze z przerzutkami dobrze jest najpierw nauczyc się dobrze chodzić.
Po prostu EF czy LINQtoSQL za dużo od razu ukrywały, nie do konca wiedzialem co gdzie i dlaczego, dlatego chce sie najpierw przeczołgac tym sposobem. co nie znaczy ze kiedys sobie to przepisze tego z uzyciem jakiegos ORM'a.//

Witam

Jak w tytule mam pytanie czym właściwie jest Agregat w podejsciu DDD, i jak go właściwie zaimplementować w moim projekcie?

Fragment bazy do którego chce podejsc jak do DDD:
http://4programmers.net/Forum/Bazy_danych/223722-relacje_zamykaja_tabele_bazy_w_petli_-_czy_to_jest_poprawne

I teraz tak, na razie zdefiniowałem anemiczne encje:
-DzialFirmy
-Stanowisko
-Uprawnienie
-Pracownik

Przykład mojej encji:

     
public class PracownikEntity : BaseEntity
    {
        public string Imie1 { get; set; }
        public string Imie2 { get; set; }
        public string Nazwisko { get; set; }
        public string Login { get; set; }
        public string MailFirmowy { get; set; }
        public string Telefon1 { get; set; }
        public string Telefon2 { get; set; }
        public int? IdBezposredniegoPrzelozonego { get; set; }
        public int? IdZajmowanegoStanowiska { get; set; }
        public int? IdDzialuFirmowego { get; set; }
        public DateTime? DataZatrudnienia { get; set; }
        public DateTime? DataZwolnienia { get; set; }
     }

Dodałem 4 odpowiadające encjom, Repository jako warstwa dostępu do bazy danych. I na razie Repository zwracają obiekty moich anemicznych encji.

Przykład mojego repozytorium:

    public class PracownikRepository : IBaseRepository<PracownikEntity>
    {
        SqlConnection conn;

        //Pozostałe metody dziedziczone po IBaseRepository

        //Przykład Add(entity)
        public void Add(PracownikEntity entity)
        {
            //wyciągnąłem do osobnego obiektu i w jednym miejscu zmieniam connection string zaleznie na ktorym komputerze aktualnie pracuje
            using (conn = new SqlConnection(DataBaseConnection.connString))  
            {
                conn.Open();
                string sql = "INSERT INTO " +
                             "Pracownik(Imie1, Imie2, Nazwisko, Login, mailFirmowy, telFirmowy1, " +
                                "telFirmowy2, idPrzelozonego, idDzialu, idStanowiska, DataZatrudnienia, DataZwolnienia) " +
                             "VALUES (@Imie1, @Imie2, @Nazwisko, @Login, @MailFirmowy, @Telefon1, " +
                                "@Telefon2, @idPrzelozonego, @idDzialu, @idStanowiska, @DataZatrudnienia, @DataZwolnienia)";

                SqlCommand cmd = new SqlCommand(sql, conn);

                cmd.Parameters.AddWithValue("@Imie1", entity.Imie1);
                cmd.Parameters.AddWithValue("@Imie2", DBTools.GetDBNULLableValue(entity.Imie2));
                cmd.Parameters.AddWithValue("@Nazwisko", entity.Nazwisko);
                cmd.Parameters.AddWithValue("@Login", entity.Login);
                cmd.Parameters.AddWithValue("@MailFirmowy", DBTools.GetDBNULLableValue(entity.MailFirmowy));
                cmd.Parameters.AddWithValue("@Telefon1", DBTools.GetDBNULLableValue(entity.Telefon1));
                cmd.Parameters.AddWithValue("@Telefon2", DBTools.GetDBNULLableValue(entity.Telefon2));
                cmd.Parameters.AddWithValue("@idPrzelozonego", DBTools.GetDBNULLableValue(entity.IdBezposredniegoPrzelozonego));
                cmd.Parameters.AddWithValue("@idDzialu", DBTools.GetDBNULLableValue(entity.IdDzialuFirmowego));
                cmd.Parameters.AddWithValue("@idStanowiska", DBTools.GetDBNULLableValue(entity.IdZajmowanegoStanowiska));
                cmd.Parameters.AddWithValue("@DataZatrudnienia", DBTools.GetDBNULLableValue(entity.DataZatrudnienia));
                cmd.Parameters.AddWithValue("@DataZwolnienia", DBTools.GetDBNULLableValue(entity.DataZwolnienia));

                cmd.ExecuteNonQuery();
                conn.Close();
            }
        }
    }

    public interface IBaseRepository<T> where T : BaseEntity
    {
        T GetById(int id);
        List<T> GetAll();
        int Count();
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
    }

    public static class DBTools
    {
        public static object GetDBNULLableValue(object value)
        {
            if (value == null)
            {
                return DBNull.Value;
            }
            return value;
        }
     }

 

Z tego co na razie się naczytałem, to Agregat rozumiem jako coś w rodzaju kontenera związanych ze sobą encji z jedną encją nadającą "charakter przewodni" dla agregatu. Dla swojego przypadku wydaje mi się że to będą agregaty:

-PracownikAgregat
-StanowiskoAgregat

Odpowiednio agregat PracownikAgregat, bedzie miał w sobie obiekt Stanowiska, **Dzialu **, Przelozonego i listę nadanych Uprawnien, bo encja wyciaga tylko ID dla tych pól.
Agregat StanowiskoAgregat bedzie mial liste obiektów Uprawnienie Domyslne dla Stanowiska i operacje na nich, dodawania, usuwanie itp.

I teraz pytanie:
Czy repository powinno zwracac od razu agregaty? tzn swoje encje mam rozwinąc, dodać do nich metody, zamiast id wyciągac od razu obiekty za pomocą innych repositoriów (np. PracownikRepository bedzie zawieralo i korzystalo z DzialRepository itp.)

czy

PracownikAgregat bedzie oddzielnym obiektem ktory bedzie zawieral przekazywana przez konstruktor encje i "opakuje" pola encji wlasnymi wlasciwosciami tylko od odczytu i metodami z logika zmieniajaca wartosci tych pól?

0
Varran napisał(a):

I teraz pytanie:
Czy repository powinno zwracac od razu agregaty? tzn swoje encje mam rozwinąc, dodać do nich metody, zamiast id wyciągac od razu obiekty za pomocą innych repositoriów (np. PracownikRepository bedzie zawieralo i korzystalo z DzialRepository itp.)

czy

PracownikAgregat bedzie oddzielnym obiektem ktory bedzie zawieral przekazywana przez konstruktor encje i "opakuje" pola encji wlasnymi wlasciwosciami tylko od odczytu i metodami z logika zmieniajaca wartosci tych pól?

Według DDD publiczne repozytoria zwracaja właśnie tylko aggregate root, a do 'dzieci' dostajesz się wlasnie z aggregate root. Jak zrobisz dostep do dzieci, to juz osobna kwestia ale ma byc to w gestii agreggate root. Mozesz pobierac od razu aggregate root ze wszystkimi dziecmi (eager loading) albo aggregate root bedzie "dobieral" swoje dzieci, gdy beda one potrzebne ("lazy loading")

0

Agregat to grupa obiektów powiązanych ze sobą biznesowo, tworzących razem całość i mających razem sens. Są one niezbędne zwłaszcza w dużych systemach, bo łatwiej się pracuje z mniejszym wycinkiem domeny niż całością. Agregatem jest np. obiekt Faktura i lista powiązanych obiektów PozycjaFaktury. Usuwając korzeń agregatu usuwasz cały agregat. Czy usuwając pracownika usuwasz też jego stanowisko, dział i przełożonego? Moim zdaniem nie.

A repozytorium to NIE jest warstwa dostępu do danych. Repozytorium znajduje się pomiędzy warstwą dostępu do danych, a domeną aplikacji: http://martinfowler.com/eaaCatalog/repository.html

0

@somekind Czyli docelowo, w moim przypadku powinno być tak, że moje repozytoria nie powinny grzebac bezpośrednio w bazie tylko np. działać na obiektach LINQtoSQL i wyciągniete dane "ubierac" w docelowe obiekty czy agregaty?

@micc Aggregate root czyli coś jak klasa bazowa? czy to jest cos innego?

2

Dla przykładu somekinda (Faktura->PozycjaFaktury) - aggregate root to Faktura.
Aggregate root to po prostu korzeń agregatu, to jedyny obiekt z całego agregatu, do którego mogą odnosić się obiekty z poza tego agregatu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1