<%@ Page Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.Data.Linq.Mapping" %>
<%@ Import Namespace="System.Data.Linq" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
switch (Request["m"])
{
case "read":
using (PlaygroundDataContext db = new PlaygroundDataContext())
{
//使用LINQ取出一筆資料物件
Member m = (from o in db.Members
where o.UserId == 1
select o).Single();
Response.Write(jss.Serialize(m));
Response.End();
}
break;
case "update":
//警告: 此處應加上CSRF防護,本範例未列出
//參考: http://bit.ly/cu0uKb, http://bit.ly/c18dsN
StreamReader sr = new StreamReader(Request.InputStream);
Member changed = jss.Deserialize<Member>(sr.ReadToEnd());
using (PlaygroundDataContext db = new PlaygroundDataContext())
{
//使用LINQ取出一筆資料物件
Member m = (from o in db.Members
where o.UserId == 1
select o).Single();
ApplyChange(m, changed);
Response.ContentType = "text/plain";
db.Log = Response.Output;
db.SubmitChanges();
Response.End();
}
break;
}
}
/// <summary>
/// 找出LINQ資料物件的Primary Key欄位名稱
/// </summary>
/// <param name="obj">LINQ資料物件</param>
/// <returns>PK欄位名稱字串陣列</returns>
public static string[] FindPrimaryKeyColNames(object obj)
{
Type t = obj.GetType();
List<string> pk = new List<string>();
foreach (PropertyInfo pi in t.GetProperties())
{
object[] atts = pi.GetCustomAttributes(true);
foreach (object att in atts)
{
ColumnAttribute colAtt = att as ColumnAttribute;
if (
att is ColumnAttribute &&
(colAtt as ColumnAttribute).IsPrimaryKey
)
pk.Add(pi.Name);
}
}
return pk.ToArray();
}
/// <summary>
/// 將物件修改值併入另一個同型別物件
/// </summary>
/// <param name="target">欲套用新值的物件</param>
/// <param name="change">內含新值的物件</param>
public static void ApplyChange(object target, object change)
{
Type t1 = target.GetType();
Type t2 = target.GetType();
//檢查二者的型別必須相同
if (t1 != t2)
throw new ApplicationException("Type dismatch!");
//找出Primary Key
string[] pk = FindPrimaryKeyColNames(target);
if (pk.Length == 0)
throw new ApplicationException("No primary key found!");
Dictionary<string, PropertyInfo> props =
new Dictionary<string, PropertyInfo>();
foreach (PropertyInfo pi in t1.GetProperties())
props.Add(pi.Name, pi);
//比對二者的PK是否相同
foreach (string c in pk)
{
PropertyInfo pi = props[c];
object v1 = pi.GetValue(target, null);
object v2 = pi.GetValue(change, null);
if (!v1.Equals(v2))
throw new ApplicationException("Primary key dismatch!");
}
//比對數值,若不相同,則進行更換,但不包含PK
foreach (PropertyInfo pi in props.Values)
{
if (pk.Contains(pi.Name)) continue;
object v1 = pi.GetValue(target, null);
object v2 = pi.GetValue(change, null);
if (!v1.Equals(v2))
pi.SetValue(target, v2, null);
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Two Phase LINQ to SQL Update</title>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.js"
type="text/javascript"></script>
<script src="json4ms.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$("#btnTest").click(function () {
$.getJSON("default.aspx", { m: "read", rnd: Math.random() },
function (m) {
m.RegTime = JSON.dateStringToDate(m.RegTime);
alert(m.UserName);
m.UserName = "X" + new Date().getMilliseconds();
$.post("default.aspx?m=update", JSON.stringify(m),
function (r) {
alert(r);
});
});
});
});
</script>
</head>
<body>
<input type="button" id="btnTest" value="Test" />
</body>
</html>