piątek, 28 grudnia 2012

[SQL|ORM] Entity Framework : Plain Old CLR Objects

Klasy generowane przez EF mają jedną zasadniczą wadę: są mocno związane z konkretnym EDM. Fakt ten ogranicza możliwości testowania i praktycznie eliminuje reużywalność. Jeżeli  chcemy skorzystać z własnych klas jako encji, mamy do dyspozycji mechanizm POCO. Nazwa Plain Old CLR oznacza mniej więcej tyle, że obiekty nie mają referencji do zewnętrznych frameworków, nie muszą dziedziczyć po żadnych specyficznych klasach.

Przykładowo, mamy zestaw tabel, mapowany przez EF na poniższy zestaw encji:


W pierwszej kolejności należy wyłączyć generowanie klas ustawiając w Designerze opcję Code Generation Strategy na None. Następnie tworzymy klasy dla encji. Każda nazwa oraz typ property (również navigation property) musi zgadzać się z nazwą z designera. Kolekcje reprezentujemy przez ISet<T>.

 public class Customer
    {
        public int CustomerId { get; set; }
        public string CustomerName { get; set; }
        public ISet<Order> Orders { get; set; }
        public Customer()
        {
            Orders = new HashSet<Order>();
        }
    }

    public class Order
    {
        public int OrderId { get; set; }
        public int CustomerId { get; set; }
        public DateTime OrderDate { get; set; }
        public Customer Customer { get; set; }
        public ISet<OrderDetail> OrderDetails { get; set; }
        public Order()
        {
            OrderDetails = new HashSet<OrderDetail>();
        }
    }

    public class OrderDetail
    {
        public int OrderId { get; set; }
        public int ProductId { get; set; }
        public decimal UnitPrice { get; set; }
        public int Quantitiy { get; set; }
        public Order Order { get; set; }
        public Product Product { get; set; }
    }

    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public decimal UnitPrice { get; set; }
    }

Ostatni krok to konieczność stworzenia klasy kontekstu.

public class EntityFrameworkRecipes : ObjectContext
{
    private ObjectSet<Customer> _customers;
    private ObjectSet<Order> _orders;
    private ObjectSet<OrderDetail> _orderdetails;
    private ObjectSet<Product> _products;

    public EntityFrameworkRecipes()
        : base("name=EntityFrameworkRecipesEntities2", "EntityFrameworkRecipesEntities2")
    {
        _orders = CreateObjectSet<Order>();
        _orderdetails = CreateObjectSet<OrderDetail>();
        _products = CreateObjectSet<Product>();
    }

    public ObjectSet<Customer> Customers
    {
        get { return _customers ?? (_customers = CreateObjectSet<Customer>()); }
    }

    public ObjectSet<Order> Orders
    {
        get { return _orders; }
    }

    public ObjectSet<OrderDetail> OrderDetails
    {
        get { return _orderdetails; }
    }

    public ObjectSet<Product> Products
    {
        get { return _products; }
    }
}

Do konstruktora bazowego przekazujemy ścieżkę do connectionstring z pliku konfiguracyjnego, oraz nazwę kontenera.

Wczytywanie encji powiązanych

Klasa ObjectContext udostępnie metodę LoadProperty i to z niej należy skorzystać, aby wczytać powiązane encje

context.LoadProperty(venue, v => v.Events);

Lazy Loading

Aby zapewnić Lazy Loading należy odpowiednie propercje w obiektach POCO oznaczyć słowem kluczowym virtual.  Dzięki temu stworzone zostaną obiekty proxy umożliwiające Lazy Loading. Dodatkowo na obiekcie kontekstu, w property ContextOptions należy ustawić opcję LazyLoadingEnabled na true.

Brak komentarzy:

Prześlij komentarz