[VS2010] ADO.NET Entity Framework: 在永續儲存無知物件實作關聯

[VS2010] 在永續儲存無知物件實作關聯

image_8

在前面的文章 [ADO.NET Entity Framework: 解構永續儲存無知物件] 中,筆者介紹了如何以純 POCO 物件的方式實作出簡單的 DAL 元件,有玩過一下的人應該都覺得簡單到一個不行 (雖然要做的事有點多,但仍比寫 SQL 簡單太多),但似乎還少了一個部份?沒錯,就是關聯 (Relationship),沒有做關聯的話,很多東西都沒有辦法實現,因此本文就來告訴大家要如何在 POCO 物件中實作關聯。

範例程式碼沿用前面 [ADO.NET Entity Framework: 解構永續儲存無知物件] 中的原始程式碼,並加入相關的程式:

 

1. 打開 Customer.cs 檔案,加入新的 POCO 物件 Order,並在 Customer 物件中加入對 Order 的巡覽屬性 (Navigation Property):

 

namespace AdoEF_CustomPoco
{
    public class Customer
    {
        public int CustomerID { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }
        public ICollection<Order> Orders { get; set; }
    }

    public class Order
    {
        public int OrderID { get; set; }
        public DateTime OrderDate { get; set; }
        public Customer Customer { get; set; }
        public int Amount { get; set; }
    }

}

 

請注意哦,在前篇文章中有提到實作 POCO 的一些原則與規定,其中有一條是 [每個一對多或多對多關聯的巡覽屬性都必須回傳實作 ICollection<T> 的型別,且 T 是另一端物件的型別。],也就是說,如果要實作出一對多的關聯的話,在一那端 (主表物件) 必須要包含一個 ICollection<T> 的屬性,而 T 就是子表物件;而子表中要有一個連結到主表物件的屬性,而型別即為主表物件的型別。在本例如,主表為 Customer,子表為 Order,所以在主表中有一個 ICollection<Order> 型別的 Orders 屬性以指向 Order 物件,Order 物件有一個 Customer 型別的 Customer 屬性以指向 Customer 物件。

 

2. 打開 CustomerModel.cs 檔案,將新物件的登錄加入 CustomerModel 中:

 

namespace AdoEF_CustomPoco
{
    public class CustomerModel : ObjectContext
    {
        public CustomerModel(EntityConnection connection)
            : base(connection)
        {
            DefaultContainerName = "CustomerModel";
        }

        public IObjectSet<Customer> CustomerItems
        {
            get { return base.CreateObjectSet<Customer>(); }
        }

        public IObjectSet<Order> OrderItems
        {
            get { return base.CreateObjectSet<Order>(); }
        }

    }
}

 

這個工作是建立 ObjectContext 與 Order 物件的關聯,讓程式碼中可以存取 Order 物件的集合。

 

3. 打開 Program.cs 檔案,加入 Order 的組態設定以及登錄資訊:

 

namespace AdoEF_CustomPoco
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContextBuilder<CustomerModel>();
            builder.Configurations.Add(new CustomerModelConfiguration());
            builder.Configurations.Add(new OrderModelConfiguration());

            var connection = new SqlConnection("initial catalog=CustomerTestDB; integrated security=SSPI");

            using (var ctx = builder.Create(connection))
            {
                if (ctx.DatabaseExists())
                    ctx.DeleteDatabase();

                ctx.CreateDatabase();

                Customer customer = new Customer() { Name = "Test", Address = "Test", Phone = "Test" };
                Order order = new Order() { Customer = customer, OrderDate = DateTime.Now, Amount = 12345 };

                ctx.CustomerItems.AddObject(customer);
                ctx.OrderItems.AddObject(order);
                ctx.SaveChanges();

            }
        }
    }

    public class CustomerModelConfiguration : EntityConfiguration<Customer>
    {
        public CustomerModelConfiguration()
        {
            Property(c => c.CustomerID).IsIdentity();
            Property(c => c.Name).HasMaxLength(103).IsRequired();
            Property(c => c.Address).Optional = true;
            Property(c => c.Phone).Optional = true;
            // map relationship
            Relationship(c => c.Orders).Optional = true;

        }
    }

    public class OrderModelConfiguration : EntityConfiguration<Order>
    {
        public OrderModelConfiguration()
        {
            Property(o => o.OrderID).IsIdentity();
            // map relationship
            Relationship(o => o.Customer).IsRequired();
            // register a reverse methos.
            Relationship(o => o.Customer).FromProperty(c => c.Orders);
        }
    }

}

 

在這裡是本範例中最重要的部份,因為關聯的設定在這裡出現。Entity Framework Configuration 利用 Relationship() 方法來讓開發人員設定物件間的關聯性,為了要讓 Entity Framework Configuration 可以捕捉到關聯物件的資訊,在 POCO 物件端就需要宣告關聯物件的資訊,這也就是為什麼要在 POCO 物件中設定關聯物件屬性的最主要原因。若沒有設定關聯屬性的話,Entity Framework Configuration 自然無從建立關聯資訊,當然也就無法產生 SQL 指令。在 Order 物件的設定需要建立指向 Customer 物件的關聯,在 Customer 物件也要設定關聯到 Order,但可以讓 Customer 物件的 Orders 保持 Optional,因為顧客不一定會有訂單。

 

設定完成後,如下圖的關聯就形成了:

 

image

 

最後,可以在程式中撰寫測試的程式碼(即上方紅字部份):

 

Customer customer = new Customer() { Name = "Test", Address = "Test", Phone = "Test" };
Order order = new Order() { Customer = customer, OrderDate = DateTime.Now, Amount = 12345 };

ctx.CustomerItems.AddObject(customer);
ctx.OrderItems.AddObject(order);
ctx.SaveChanges();

 

就目前 Entity Framework Team 所公布的資訊來看,雖然已經可以做到建立關聯,但還沒有辦法直接實作出 Foreign Key Association,因此暫時還無法利用像 Customer.Orders.Add() 的方式來插入關聯物件,既然 EDM Model Designer 都已經有了 FK Association 的能力,筆者當然也會希望 POCO 物件端也可以支援這樣的功能,不過這一切都要看 Entity Framework Team 的能耐。

 

參考資料:

Feature CTP Walkthrough: Code Only for the Entity Framework

http://blogs.msdn.com/adonet/pages/feature-ctp-walkthrough-code-only-for-the-entity-framework.aspx