博客園現代化建設—用 Entity Framework 與 Json.NET 實現數據的按需更新
上篇隨筆中,我們留下了一個難題——如何將客戶端瀏覽器通過ajax提交的json數據傳遞給一個已存在的實體對象(也就是將json數據賦值給實體對象對應的屬性)。這樣的話,Entity Framework就能自動發現哪些屬性值發生了變化,在保存時,只將發生變化的屬性值更新至對應的數據庫字段。
需要注意的是這里提交的json數據中的屬性是動態的,不一定包含實體對象的所有屬性,比如:這次提交的是{"Title":"Hello World"},下次提交的是{"Title":"Hello World","Description":"This is a test."}。第一種情況對應的應用場景是,博客后臺提供一個快速修改標題的功能,通過彈出層彈出一個修改標題的文本框完成修改。
在這里再強調一下Entity Framework如何實現按需更新。先給它一個修改前的實體對象,然后修改當前這個對象的屬性值,EF才能跟蹤所做的修改,并在保存時更新至數據庫。
面對這個難題,你也許想到了這樣一種方法。直接將json數據反序列化為實體對象(ASP.NET MVC的控制器可以自動完成這個反序列化),然后將這個對象的屬性值復制給EF跟蹤的實體對象。但是,你不知道這個反序列化出來的對象的哪些屬性值是來自json數據的。全部復制也不可行,前面已經說明過json數據中的屬性是動態的,這個反序列化出來的對象并不是完整的實體對象。如果強行全部復制,更新時,會造成json數據中未包含的屬性的數據丟失。
我們采用的解決方法是:通過Json.NET獲取json數據中的屬性,然后通過反射去修改被EF跟蹤的實體對象的對應的屬性值。
下面我們通過代碼示例說明一下我們的解決方法。
客戶端瀏覽器中通過ajax提交json數據的js代碼:
function update_post() {
var post = {};
post.Title = $.trim($("#txtTitle").val());
post.Description = $.trim($("#txtDescription").val());
var jsonStr = JSON.stringify(post);
var entry = {};
entry.postId = entryId;
entry.jsonData = jsonStr;
$.ajax({
url: '/admin/AjaxUpdatePost.aspx',
data: JSON.stringify(entry),
success: update_post_callback
});
}
實際提交的json數據:
{"postId":3560,"jsonData":"{\"Title\":\"hello world\",\"Description\":\"test\"}"}
ASP.NET MVC Controller中的代碼:
[HttpPost]
public JsonResult AjaxUpdatePost(int postId, string jsonData)
{
return Json(ServiceFactory.BlogEntryService.Update(postId, jsonData));
}
業務邏輯層中的代碼:
public class BlogEntryManager
{
//實體對象數據更新
public bool Update(int postId, string jsonData)
{
BlogPost originalPost = GetBlogPost(postId);
using (BlogDbContext context = new BlogDbContext())
{
context.BlogPosts.Attach(originalPost);
JsonToObject(originalPost, jsonData);
context.SaveChanges();
}
return true;
}
//Json數據復制給實體對象
private void JsonToObject(BlogPost post, string jsonData)
{
JObject jo = JObject.Parse(jsonData);
var postType = post.GetType();
foreach (var proper in jo.Properties())
{
postType.GetProperty(proper.Name).SetValue(post, (string)proper.Value, null);
}
}
//獲取修改前的實體對象
public BlogPost GetBlogPost(int entryId)
{
using (BlogDbContext context = new BlogDbContext())
{
var result = from p in context.BlogPosts
where p.ID == entryId && p.IsExist
select p;
return result.FirstOrDefault();
}
}
}
代碼通過測試,已經驗證了能夠滿足我們目前的需求。
博客園現代化建設又向前邁進了一步!
浙公網安備 33010602011771號