niedziela, 15 sierpnia 2010

POCO w Entity Framework

Entity Framework w wersji 1.0 pozbawiony był dwóch ważnych aspektów. Po pierwsze brakowało w nim "Persistence Ignorance" czyli odrzucamy konieczność informacji w jaki sposób przechowywane w bazie danych są nasze obiekty. Drugim ważnym aspektem był brak POCO - Plain Old Clr Objects. POCO odseparowuje nas od konieczności używania jednego narzędzia ORM. Dzięki temu mamy możliwość użycia innych maperów  do tworzenia naszych klas. Przekłada się to również na większą re-używalność stworzonego kodu. Innym aspektem jest testowanie. Testowanie POCO jest łatwiejsze, gdyż nie ma zbędnych powiązań pomiędzy klasami.

Zaletą którą szczególnie sobie cenię jest to, że sam mogę zaprojektować klasy mapujące tabele w bazie danych. Daje mi to możliwość łatwego ich wykorzystania w aplikacjach webowych opartych o MVC. Designer za każdym razem generując kod usuwa wszystkie znaczniki. Tak więc dodając swoje znaczniki (np. walidację) po każdym buildzie Designera nasze znaczniki znikają. Dzięki POCO nie dojdzie do takiej sytuacji.

W Entity Framework 4.0 naprawiono te błędy i wprowadzono rzeczy  których wcześniej wspomniałem.

Pokażę w praktyce jak tworzyć takie obiekty i jak nimi operować.
Podczas tworzenia obiektów POCO mamy do czynienia z czterema standardowymi krokami:
1. Dodajemy do naszego projektu ADO.NET Entity Data Model i standardowo przechodzimy przez Wizard tworzący pliki schemadu edmx.

2. We właściwościach projektu EF zaznaczamy CodeGenerationStrategy = None:

Ustawienie to zapobiegnie tworzenia kodu przez generator. Teraz możemy zbudować nasz projekt i przejdziemy to tworzenia klasy POCO dla naszej tabeli Person.

3. Tworzymy nową klasy które odpowiadają tym stworzonym przez Designer (namespace nie jest brany pod uwagę). Jedną rzeczą na którą musimy zwrócić szczególną uwagę to nazwy pól i typy - nie zachowanie ich spowoduje szereg błędów czasami trudnych do odnalezienia.  Tworzymy więc klasę Person:

    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }
        public string PhoneNumber { get; set; }
    }

W przypadku klasy w której mamy do czynienia z kolekcjami - czyli relacje jeden do wielu, tworzymy pole typu List ze słowem kluczowym virtual. Zapewnia to zachowanie Lazy Loading.

4. Tworzymy klasę dziedziczącą po ObjectContext która będzie połączeniem pomiędzy nami a bazą danych:

    class PocoObjectContext : ObjectContext
    {
        private ObjectSet<Person> _persons;

        public ObjectSet<Person> Persons
        {
            get { return _persons; }
            set { _persons = value; }
        }

        public PocoObjectContext()
            : base("name=POCO_Entity_FrameworkEntities", "POCO_Entity_FrameworkEntities")
        {
            _persons = CreateObjectSet<Person>();
        }
    }

Teraz czas na test naszego rozwiązania:

            //Zapisujemy do bazy nową osobę
            Person p = new Person
            {
                Id = 1,
                FirstName = "Marek",
                LastName = "Kowalski",
                PhoneNumber = "15665236",
                DateOfBirth = DateTime.Now.AddYears(-15).AddDays(-26).AddMonths(-3)
            };

            PocoObjectContext db = new PocoObjectContext();
            db.Persons.AddObject(p);
            db.SaveChanges();

            //Odczyt z bazy
            var q = from a in db.Persons
                    select a;
            foreach (var item in q)
            {
                Console.WriteLine("{0} {1} {2} {3}", item.FirstName, item.LastName, item.PhoneNumber, item.DateOfBirth.ToString("d"));
            }


Jak widać nic trudnego a i możliwości są bardzo duże. Możemy także skorzystać z gotowych generatorów dostarczonych przez Microsoft. Generator jest w taki sposób opracowany, że działa na zasadzie szablonów. Możemy wiec dostosować generowany kod do naszych potrzeb.

1 komentarz: