使用 Entity Framework 新增一筆資料是極其簡單的事。然而建立相關聯的資料呢?也相當簡單!以下介紹常見的狀況。
DataSchema
在這個範例中,使用最簡單的 master-detail 的資料表。一個是 Order,一個是 OrderDetail。Sql Script 如下
CREATE TABLE [dbo].[Order](
[OrderId] [int] IDENTITY(1,1) NOT NULL,
[OrderDate] [datetime] NOT NULL,
CONSTRAINT [PK_Order] PRIMARY KEY CLUSTERED
(
[OrderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
go
CREATE TABLE [dbo].[OrderDetail](
[DetailId] [int] IDENTITY(1,1) NOT NULL,
[OrderId] [int] NOT NULL,
[ProductName] [nchar](50) COLLATE Chinese_Taiwan_Stroke_CI_AS NOT NULL,
CONSTRAINT [PK_OrderDetail] PRIMARY KEY CLUSTERED
(
[DetailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
go
ALTER TABLE [dbo].[OrderDetail] WITH CHECK ADD CONSTRAINT [FK_OrderDetail_Order] FOREIGN KEY([OrderId])
REFERENCES [dbo].[Order] ([OrderId])
GO
ALTER TABLE [dbo].[OrderDetail] CHECK CONSTRAINT [FK_OrderDetail_Order]
GO
範例一
以下是最簡單的方法,也是基本上我認為這樣的寫法最適當
class Program
{
static void Main(string[] args)
{
AddData1();
ShowData();
}
private static void ShowData()
{
using (Database1Entities context = new Database1Entities())
{
var orders = context.Orders.Include("OrderDetails");
foreach (var order in orders)
{
Console.WriteLine("order id = {0}", order.OrderId);
foreach (var d in order.OrderDetails)
Console.WriteLine("detail prod={0}", d.ProductName);
}
}
}
private static void AddData1()
{
using (Database1Entities context = new Database1Entities())
{
var order = new Order() {
OrderDate = new DateTime(2010, 4, 12)
};
var detail = new OrderDetail {
ProductName = "Prod1"
};
order.OrderDetails.Add(detail);
context.Orders.AddObject(order);
context.SaveChanges();
}
}
}
要注意的是,我們使用了 order.OrderDetails.Add(detail) 將order 與 detail 的關聯建立起來。接下來使用 context.Orders.AddObject(order) 將 order 新增到 context 中,因此當 context.SaveChanges() 時,context 會查覺到 order 是新增的資料,才會將資料寫到資料庫中。
這樣的方法相當完美,原因在開發人員只需關注物件模型的關係即可,不必知道物件模型關聯的 key 是哪一個 property。
範例二
下面的方法也可以執行。
private static void AddData2()
{
using (Database1Entities context = new Database1Entities())
{
var order = new Order()
{
OrderDate = new DateTime(2010, 4, 12)
};
context.Orders.AddObject(order);
context.SaveChanges();
var detail = new OrderDetail
{
OrderId = order.OrderId,
ProductName = "Prod1"
};
context.OrderDetails.AddObject(detail);
context.SaveChanges();
}
}
與範例一不同的是,範例二並不強調 order 與 detail 的物件關聯,而是直接指定 detail 的 OrderId。因此order 與 detail 是分開寫入資料庫的。
範例二就是比較差的寫法了,原因是在開發人員需要了解關聯的property 為何,此例為 OrderDetai 的 OrderId 關聯到 Order 的 OrderId。長久下來,開發人員會習慣以 Data driven 的寫作方式看待 Entity Framework,故不建議這樣做。
範例三
範例三與範例二大致相同
private static void AddData3()
{
using (Database1Entities context = new Database1Entities())
{
var order = new Order()
{
OrderDate = new DateTime(2010, 4, 12)
};
context.Orders.AddObject(order);
context.SaveChanges();
var detail = new OrderDetail
{
Order = order, //這一行換了
ProductName = "Prod1"
};
context.OrderDetails.AddObject(detail);
context.SaveChanges();
}
}
範例三與範例二的概念相同。原來範例二中 detail 是指定 OrderId ,而範例三中 detail 改指定 Order 為 order
只增加 Detail
如果已經知道 master 的 primary key,只想新增 detail 的資料呢?下面的範例四是可以執行的。
範例四
static void Main(string[] args)
{
AddData1();
AddNewDetail1();
ShowData();
}
private static void AddNewDetail1()
{
using (Database1Entities context = new Database1Entities())
{
var order = context.Orders.Where(o => o.OrderId == 1).First();
var detail = new OrderDetail
{
ProductName = "Prod2"
};
order.OrderDetails.Add(detail);
context.SaveChanges();
}
}
因為物件模型的關係,範例四的做法相當直覺,也相當多的開發人員這樣寫。但是,我們已經知道了 OrderId 為1,範例四會先載入 OrderId 為1的資料並載入記憶體,再進行後續的新增detail 動作。這樣一來,反而效能不彰。可不可以像以前一樣,直接新增一筆 OrderDetail 就好了,不需要載入 Order 啊?
下面的範例五可以在不載入 master (即 order) 到記憶體的情況下增加 detail 資料。
範例五
static void Main(string[] args)
{
AddData1();
AddNewDetail();
ShowData();
}
private static void AddNewDetail()
{
using (Database1Entities context = new Database1Entities())
{
var detail = new OrderDetail
{
OrderId = 1, //指定了 master 的 key
ProductName = "Prod2"
};
context.OrderDetails.AddObject(detail);
context.SaveChanges();
}
}
結論
在 Entity Framework 中,關聯資料的寫法可以有相當多種,但其中的差別需要開發人員注意哦!
6 則留言:
hi..大大你好
請問這邊範例
是EF1還是EF4的Code阿?
我使用的是 EF 4
瞭解
想說EF1應該Gen不出OrderDetail.OrderId這個屬性才對
EF4有這種特性真的滿方便的^^
在研究 MS Nerd Dinner. 不太清楚Add與AddObject的差異. 看了您的文章就懂了. 感恩啦!
謝版主. 小的剛從Fat client轉到asp.net.小的認為EF好像是特地為MVC打造的. 像這一行
var orders = context.Orders.Include("OrderDetails");
直接由controller拋orders到view. 資料就跑出來了.
您好!
請問一下,
如果我開好的 Entity 當中,
OrderDetail 沒有 OrderId的屬性,
是否開錯了呢?!
張貼留言