ADO.NET Entity Framework 4.0 Self Tracking Entity
介紹
ADO.NET Entity Framework 4.0 的新增功能
* 對 Self Tracking Entity(實體狀態自跟蹤)的支持,基於 POCO
* WCF 結合 Self Tracking Entity 的應用
示例
1、Self Tracking Entity 的 Demo
SelfTrackingDemo/BLL.cs
代碼
/*
* ADO.NET Entity Framework 4.0 - 對 Self Tracking Entity(實體狀態自跟蹤)的支持,基於 POCO
* 1、不通過 WCF 使用 Self Tracking Entity 需要手動調用 StartTracking()
* 2、MarkAsAdded(), MarkAsModified(), MarkAsDeleted() 會自動 StartTracking()
* 3、ApplyChanges() 的作用是:綁定實體到上下文,通過 ChangeObjectState 改變實體的狀態,通過 ChangeRelationshipState 改變關聯實體的狀態
*
* 本 Demo 演示如何通過 Self Tracking Entity 來實現對單表的增刪改查
* 如果涉及到關聯實體,可以參考 http://www.cnblogs.com/webabcd/archive/2010/06/17/1759314.html 中的“對外 鍵的支持”的 Demo
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SelfTrackingDemo
{
public class BLL
{
// 取全部產品類別的實體集合
public List<ProductCategory> GetCategories()
{
using (SelfTrackingEntities ctx = new SelfTrackingEntities())
{
var result = ctx.ProductCategories.ToList();
return result;
}
}
// 根據 id 取產品類別實體
public ProductCategory GetCategory(int categoryId)
{
using (SelfTrackingEntities ctx = new SelfTrackingEntities())
{
var result = ctx.ProductCategories.Single(c => c.ProductCategoryID == categoryId);
return result;
}
}
// 根據產品類別實體更新數據庫中的相關數據
public void UpdateCategory(ProductCategory category)
{
using (SelfTrackingEntities ctx = new SelfTrackingEntities())
{
// ApplyChanges() 的內部邏輯為:綁定實體到上下文,通過 ChangeObjectState 改變實體 的狀態,通過 ChangeRelationshipState 改變關聯實體的狀態
ctx.ProductCategories.ApplyChanges(category);
// 根據實體的狀態,實現對實體的 添加、更新、刪除 操作
var affectedRow = ctx.SaveChanges();
}
}
// 根據產品類別實體刪除數據庫中的相關數據
public void DeleteCategory(ProductCategory category)
{
// 標記該實體為刪除狀態
category.MarkAsDeleted();
UpdateCategory(category);
}
// 根據產品類別實體向數據庫添加新的數據
public void AddCategory(ProductCategory category)
{
UpdateCategory(category);
}
}
}
SelfTrackingDemo/Demo.aspx
代碼
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Demo.aspx.cs" Inherits="SelfTrackingDemo.Demo" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ListView ID="ListView1" runat="server" DataSourceID="ObjectDataSource1" DataKeyNames="ProductCategoryID"
InsertItemPosition="LastItem" OnItemUpdating="ListView1_ItemUpdating">
<EditItemTemplate>
<tr style="">
<td>
<asp:Button ID="UpdateButton" runat="server" CommandName="Update" Text="Update" />
<asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" />
</td>
<td>
</td>
<td>
</td>
<td>
<asp:TextBox ID="NameTextBox" runat="server" Text='<%# Bind("Name") %>' />
</td>
<td>
</td>
<td>
</td>
</tr>
</EditItemTemplate>
<InsertItemTemplate>
<tr style="">
<td>
<asp:Button ID="InsertButton" runat="server" CommandName="Insert" Text="Insert" />
<asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Clear" />
</td>
<td>
</td>
<td>
</td>
<td>
<asp:TextBox ID="NameTextBox" runat="server" Text='<%# Bind("Name") %>' />
</td>
<td>
</td>
<td>
</td>
</tr>
</InsertItemTemplate>
<ItemTemplate>
<tr style="">
<td>
<asp:Button ID="DeleteButton" runat="server" CommandName="Delete" Text="Delete" />
<asp:Button ID="EditButton" runat="server" CommandName="Edit" Text="Edit" />
</td>
<td>
<asp:Label ID="ProductCategoryIDLabel" runat="server" Text='<%# Eval("ProductCategoryID") %>' />
</td>
<td>
<asp:Label ID="ParentProductCategoryIDLabel" runat="server" Text='<%# Eval("ParentProductCategoryID") %>' />
</td>
<td>
<asp:Label ID="NameLabel" runat="server" Text='<%# Eval("Name") %>' />
</td>
<td>
<asp:Label ID="rowguidLabel" runat="server" Text='<%# Eval("rowguid") %>' />
</td>
<td>
<asp:Label ID="ModifiedDateLabel" runat="server" Text='<%# Eval("ModifiedDate") %>' />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" style="">
<tr runat="server" style="">
<th runat="server">
</th>
<th runat="server">
ProductCategoryID
</th>
<th runat="server">
ParentProductCategoryID
</th>
<th runat="server">
Name
</th>
<th runat="server">
rowguid
</th>
<th runat="server">
ModifiedDate
</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DataObjectTypeName="SelfTrackingDemo.ProductCategory"
DeleteMethod="DeleteCategory" InsertMethod="AddCategory" SelectMethod="GetCategories"
TypeName="SelfTrackingDemo.BLL" OnInserting="ObjectDataSource1_Inserting" OnDeleting="ObjectDataSource1_Deleting">
</asp:ObjectDataSource>
</div>
</form>
</body>
</html>
SelfTrackingDemo/Demo.aspx.cs
代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SelfTrackingDemo
{
public partial class Demo : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ObjectDataSource1_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
var category = e.InputParameters[0] as ProductCategory;
category.rowguid = Guid.NewGuid();
category.ModifiedDate = DateTime.Now;
}
protected void ObjectDataSource1_Deleting(object sender, ObjectDataSourceMethodEventArgs e)
{
}
protected void ListView1_ItemUpdating(object sender, ListViewUpdateEventArgs e)
{
BLL bll = new BLL();
var category = bll.GetCategory((int)ListView1.DataKeys[e.ItemIndex].Value);
// 注意:這裡一定要手動調用 StartTracking() 方法,用於跟蹤實體狀態的改變
category.StartTracking();
category.Name = e.NewValues["Name"].ToString();
bll.UpdateCategory(category);
ListView1.EditIndex = -1;
e.Cancel = true;
}
}
}
2、WCF 結合 Self Tracking Entity 的 Demo
服務端:NTierServer/IMyService.cs
代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace NTierServer
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
List<ProductCategory> GetCategories();
[OperationContract]
ProductCategory GetCategory(int categoryId);
[OperationContract]
int UpdateCategory(ProductCategory category);
[OperationContract]
int AddCategory(ProductCategory category);
[OperationContract]
int DeleteCategory(int categoryId);
}
}
服務端:NTierServer/MyService.cs
代碼
/*
* ADO.NET Entity Framework 4.0 - WCF 結合 Self Tracking Entity 的應用
* 1、通過 WCF 使用 Self Tracking Entity 不需手動調用 StartTracking()
* 2、先 MarkAsAdded(), MarkAsModified(), MarkAsDeleted() 再 ApplyChanges() ; 或者 先 ApplyChanges() 再 ChangeObjectState(), ChangeRelationshipState()
*
* 本 Demo 演示如何通過 WCF 結合 Self Tracking Entity 來實現對單表的增刪改查
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Data;
namespace NTierServer
{
public class MyService : IMyService
{
// 取全部產品類別的實體集合
public List<ProductCategory> GetCategories()
{
using (var ctx = new AdventureWorksEntities())
{
var result = ctx.ProductCategories.ToList();
return result;
}
}
// 根據 id 取產品類別實體
public ProductCategory GetCategory(int categoryId)
{
using (var ctx = new AdventureWorksEntities())
{
var result = ctx.ProductCategories.Single(c => c.ProductCategoryID == categoryId);
return result;
}
}
// 根據產品類別實體更新數據庫中的相關數據
public int UpdateCategory(ProductCategory category)
{
using (var ctx = new AdventureWorksEntities())
{
// 先 ApplyChanges() 再 ChangeObjectState(), ChangeRelationshipState()
ctx.ProductCategories.ApplyChanges(category);
ctx.ObjectStateManager.ChangeObjectState(category, EntityState.Modified);
return ctx.SaveChanges();
}
}
// 根據產品類別實體向數據庫添加新的數據
public int AddCategory(ProductCategory category)
{
using (var ctx = new AdventureWorksEntities())
{
ctx.ProductCategories.ApplyChanges(category);
return ctx.SaveChanges();
}
}
// 根據 id 刪除數據庫中的相關數據
public int DeleteCategory(int categoryId)
{
using (var ctx = new AdventureWorksEntities())
{
var category = GetCategory(categoryId);
// 先 MarkAsAdded(), MarkAsModified(), MarkAsDeleted() 再 ApplyChanges()
category.MarkAsDeleted();
ctx.ProductCategories.ApplyChanges(category);
return ctx.SaveChanges();
}
}
}
}
服務端:NTierServer/Web.config
代碼
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
客戶端:NTierClient/Web.config
代碼
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMyService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:10394/MyService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMyService" contract="MyServiceReference.IMyService"
name="BasicHttpBinding_IMyService" />
</client>
</system.serviceModel>
客戶端:NTierClient/Demo.aspx
代碼
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Demo.aspx.cs" Inherits="NTierClient.Demo" % >
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ProductCategoryID" InsertItemPosition="LastItem"
OnItemDeleting="ListView1_ItemDeleting" OnItemInserting="ListView1_ItemInserting"
OnItemUpdating="ListView1_ItemUpdating" OnItemCanceling="ListView1_ItemCanceling"
OnItemEditing="ListView1_ItemEditing">
<EditItemTemplate>
<tr style="">
<td>
<asp:Button ID="UpdateButton" runat="server" CommandName="Update" Text="Update" />
<asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" />
</td>
<td>
</td>
<td>
</td>
<td>
<asp:TextBox ID="NameTextBox" runat="server" Text='<%# Bind("Name") %>' />
</td>
<td>
</td>
<td>
</td>
</tr>
</EditItemTemplate>
<InsertItemTemplate>
<tr style="">
<td>
<asp:Button ID="InsertButton" runat="server" CommandName="Insert" Text="Insert" />
<asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Clear" />
</td>
<td>
</td>
<td>
</td>
<td>
<asp:TextBox ID="NameTextBox" runat="server" Text='<%# Bind("Name") %>' />
</td>
<td>
</td>
<td>
</td>
</tr>
</InsertItemTemplate>
<ItemTemplate>
<tr style="">
<td>
<asp:Button ID="DeleteButton" runat="server" CommandName="Delete" Text="Delete" />
<asp:Button ID="EditButton" runat="server" CommandName="Edit" Text="Edit" />
</td>
<td>
<asp:Label ID="ProductCategoryIDLabel" runat="server" Text='<%# Eval("ProductCategoryID") %>' />
</td>
<td>
<asp:Label ID="ParentProductCategoryIDLabel" runat="server" Text='<%# Eval("ParentProductCategoryID") %>' />
</td>
<td>
<asp:Label ID="NameLabel" runat="server" Text='<%# Eval("Name") %>' />
</td>
<td>
<asp:Label ID="rowguidLabel" runat="server" Text='<%# Eval("rowguid") %>' />
</td>
<td>
<asp:Label ID="ModifiedDateLabel" runat="server" Text='<%# Eval("ModifiedDate") %>' />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" style="">
<tr runat="server" style="">
<th runat="server">
</th>
<th runat="server">
ProductCategoryID
</th>
<th runat="server">
ParentProductCategoryID
</th>
<th runat="server">
Name
</th>
<th runat="server">
rowguid
</th>
<th runat="server">
ModifiedDate
</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
客戶端:NTierClient/Demo.aspx.cs
代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ServiceModel;
namespace NTierClient
{
public partial class Demo : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
BindData();
}
}
private void BindData()
{
var svc = new ChannelFactory<MyServiceReference.IMyService> ("BasicHttpBinding_IMyService").CreateChannel();
var categories = svc.GetCategories();
ListView1.DataSource = categories;
ListView1.DataBind();
}
protected void ListView1_ItemUpdating(object sender, ListViewUpdateEventArgs e)
{
var svc = new MyServiceReference.MyServiceClient();
var category = svc.GetCategory((int)ListView1.DataKeys[e.ItemIndex].Value);
category.Name = (string)e.NewValues["Name"];
svc.UpdateCategory(category);
ListView1.EditIndex = -1;
BindData();
}
protected void ListView1_ItemInserting(object sender, ListViewInsertEventArgs e)
{
var category = new MyServiceReference.ProductCategory();
category.Name = (string)e.Values["Name"];
category.rowguid = Guid.NewGuid();
category.ModifiedDate = DateTime.Now;
var svc = new MyServiceReference.MyServiceClient();
svc.AddCategory(category);
BindData();
}
protected void ListView1_ItemDeleting(object sender, ListViewDeleteEventArgs e)
{
var svc = new MyServiceReference.MyServiceClient();
svc.DeleteCategory((int)ListView1.DataKeys[e.ItemIndex].Value);
BindData();
}
protected void ListView1_ItemCanceling(object sender, ListViewCancelEventArgs e)
{
ListView1.EditIndex = -1;
BindData();
}
protected void ListView1_ItemEditing(object sender, ListViewEditEventArgs e)
{
ListView1.EditIndex = e.NewEditIndex;
BindData();
}
}
}