為什麼要以對象的方式來訪問xml數據表? 還記得,自己是在一次完成師兄佈置的任務時接觸到了xml,那時候需要用xml來作為數據文件,保存一個簡單的圖書管理系統的數據。於是就知道了,可以用xml文件來保存數據(而且比用簡單的文本文件保存數據規範的多,在訪問與讀取數據上面都十分方便),就這樣使用xml的 ...
為什麼要以對象的方式來訪問xml數據表?
還記得,自己是在一次完成師兄佈置的任務時接觸到了xml,那時候需要用xml來作為數據文件,保存一個簡單的圖書管理系統的數據。於是就知道了,可以用xml文件來保存數據(而且比用簡單的文本文件保存數據規範的多,在訪問與讀取數據上面都十分方便),就這樣使用xml的徵程開始了。
自己做的第一個WPF桌面應用程式——備忘錄,就是用xml文件作為資料庫。而且那個時候考慮到以後可能會經常使用到xml文件作為資料庫,於是乎就寫了一個專門用於訪問xml文件的動態鏈接庫,這樣不僅可以提高代碼的重用性(用功一次,獲益無窮),而且還提高了軟體後期的維護效率(由於規範),動態鏈接庫實現的基本功能:將連接數據文件的過程和檢查規範全封裝在一個方法裡面(而數據表的屬性是通過數組傳參傳遞),將對數據的增、刪、查、改也全部封裝成各種方法,還封裝了一些屬性等等。但此時的自己還沒有面向對象開發的思維,最終在開發時還是以傳統的方式去訪問的xml數據表(Element(value))。
這是我第一個版本的訪問xml的動態鏈接庫源碼:
using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using System.IO; using System.Text.RegularExpressions; namespace XmlIDataBase { public class XmlDataBase { #region 私有欄位 private string xmlFilePath; private string[] xmlProperties; private string noteName; #endregion #region 公有欄位 public XElement Notes; #endregion #region 公有方法 //連接數據文件 public bool Connect(string path_, string noteName_, params string[] properties) { try { //匹配xml文件路徑 if (!Regex.IsMatch(path_, @"^(?<fpath>([a-zA-Z]:\\)([\s\.\-\w]+\\)*)(?<fname>[\w]+.[\w]+)") || noteName_ == "" || path_.Length < 5 || path_.Substring(path_.Length - 3).ToLower() != "xml") { return false; } noteName = noteName_;//記錄每條記錄的名稱 xmlFilePath = path_;//記錄文件路徑 if (path_.LastIndexOf("\\") > 0) { path_ = path_.Substring(0, path_.LastIndexOf("\\")); } else { path_ = ""; } if (path_ != "" && !Directory.Exists(path_)) { Directory.CreateDirectory(path_); var xmlFile = new StreamWriter(xmlFilePath); xmlFile.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); xmlFile.WriteLine("<" + noteName + "s>"); xmlFile.WriteLine("</" + noteName + "s>"); xmlFile.Close(); } else { if (!File.Exists(xmlFilePath)) { var xmlFile = new StreamWriter(xmlFilePath); xmlFile.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); xmlFile.WriteLine("<" + noteName + "s>"); xmlFile.WriteLine("</" + noteName + "s>"); xmlFile.Close(); } } Notes = XElement.Load(xmlFilePath); xmlProperties = new string[properties.Length]; xmlProperties = properties;//記錄每條記錄的屬性 return true; } catch (Exception e) { throw e; //return false; } } //保存數據文件 public bool SaveChanged() { try { Notes.Save(xmlFilePath); return true; } catch (Exception e) { throw e; //return false; } } //添加紀錄:添加到末尾(方法一) public bool AddNote(params string[] propertyValues) { try { if (propertyValues.Length == xmlProperties.Length) { if (Notes.Elements(noteName).Count() > 0) { int newNo; var lastNote = from Note in Notes.Elements() select Convert.ToInt32(Note.Attribute("No").Value); newNo = lastNote.Max() + 1; Notes.LastNode.AddAfterSelf(noteName, new XAttribute("No", newNo)); for (int i = 0; i < xmlProperties.Length; i++) { if (i == 0) { Notes.Elements().Last().AddFirst(new XElement(xmlProperties[i], propertyValues[i])); } else { Notes.Elements().Last().LastNode.AddAfterSelf(new XElement(xmlProperties[i], propertyValues[i])); } } } else { Notes.AddFirst(new XElement(noteName, new XAttribute("No", 1))); for (int i = 0; i < xmlProperties.Length; i++) { if (i == 0) { Notes.Element(noteName).AddFirst(new XElement(xmlProperties[i], propertyValues[i])); } else { Notes.Element(noteName).LastNode.AddAfterSelf(new XElement(xmlProperties[i], propertyValues[i])); } } } return true; } else { return false; } } catch (Exception e) { throw e; //return false; } } //添加記錄:添加到末尾(方法二) public bool AddNote(XElement newNote) { try { if (newNote.Elements().Count() == xmlProperties.Length) { if (Notes.Elements(noteName).Count() > 0) { int newNo; var lastNote = from Note in Notes.Elements() select Convert.ToInt32(Note.Attribute("No").Value); newNo = lastNote.Max() + 1; if(newNote.Attribute("No") == null) { newNote.Add(new XAttribute("No", newNo)); } else { newNote.Attribute("No").Value = newNo.ToString(); } Notes.Elements().Last().AddAfterSelf(newNote); } else { if (newNote.Attribute("No") == null) { newNote.Add(new XAttribute("No", 1)); } else { newNote.Attribute("No").Value = "1"; } Notes.AddFirst(newNote); } return true; } else { return false; } } catch (Exception e) { throw e; //return false; } } //添加記錄:添加到開頭 public bool AddFistNote(XElement newNote) { try { if (newNote.Elements().Count() == xmlProperties.Length) { if (Notes.Elements(noteName).Count() > 0) { int newNo; var lastNote = from Note in Notes.Elements() select Convert.ToInt32(Note.Attribute("No").Value); newNo = lastNote.Max() + 1; if (newNote.Attribute("No") == null) { newNote.Add(new XAttribute("No", newNo)); } else { newNote.Attribute("No").Value = newNo.ToString(); } Notes.AddFirst(newNote); } else { if (newNote.Attribute("No") == null) { newNote.Add(new XAttribute("No", 1)); } else { newNote.Attribute("No").Value = "1"; } Notes.AddFirst(newNote); } return true; } else { return false; } } catch (Exception e) { throw e; //return false; } } //刪除記錄(單一索引) public bool DeletNote(string no = "", params string[] propertyValues) { try { bool okFlag = false; if (propertyValues.Length > xmlProperties.Length) { return false; } else { if (no == "") //按屬性值相等刪除 { for (int i = 0; i < propertyValues.Length; i++) { if (propertyValues[i] == "") continue; if (Notes.Elements(noteName).Count() == 0) return false;//數據文件內容為空 var proNotes = Notes.Elements(noteName).Elements(xmlProperties[i]).Where(m => m.Value == propertyValues[i]); foreach (var item in proNotes) { item.Parent.Remove(); okFlag = true; } } } else //按編號相等刪除 { if (Notes.Elements(noteName).Count() == 0) return false;//數據文件內容為空 var proNote = Notes.Elements(noteName).SingleOrDefault(m => m.Attribute("No").Value == no); if (proNote != null) { proNote.Remove(); okFlag = true; } } return okFlag; } } catch (Exception e) { throw e; //return false; } } //修改記錄(編號索引:方法一) public bool ModifyNote(string no, params string[] propertyValues) { try { if (no == "" || propertyValues.Length != xmlProperties.Length) { return false; } bool okFlag = false; if (Notes.Elements(noteName).Count() == 0) return false;//數據文件內容為空 var proNote = Notes.Elements(noteName).Attributes("No").SingleOrDefault(m => m.Value == no); if (proNote != null) { var proSubNotes = proNote.Parent.Elements(); int i = 0; foreach (var item in proSubNotes) { item.Value = propertyValues[i++]; } okFlag = true; } return okFlag; } catch (Exception e) { throw e; //return false; } } //修改記錄(編號索引:方法二用一個新的節點(No值不變)替代) public bool ModifyNote(string no, XElement noteModified) { try { if (no == "" || noteModified.Elements().Count() != xmlProperties.Length) { return false; } bool okFlag = false; if (Notes.Elements(noteName).Count() == 0) return false;//數據文件內容為空 var proNote = Notes.Elements(noteName).Attributes("No").SingleOrDefault(m => m.Value == no); if (proNote != null) { proNote.Parent.ReplaceWith(noteModified); } return okFlag; } catch (Exception e) { throw e; //return false; } } //查詢記錄(單一索引) public IEnumerable<XElement> QueryNote(string no = "", params string[] propertyValues) { IEnumerable<XElement> result = null; try { if (no == "" && propertyValues.Length == 0)//返回所有數據 { return Notes.Elements(noteName); } if (no == "" && propertyValues.Length != 0) { for (int i = 0; i < propertyValues.Length; i++) { if (propertyValues[i] == "") continue; if (Notes.Elements(noteName).Count() == 0) return result;//數據文件內容為空 var proNotes = Notes.Elements(noteName).Elements(xmlProperties[i]).Where(m => m.Value == propertyValues[i]); return proNotes; } } else { if (Notes.Elements(noteName).Count() == 0) return result;//數據文件內容為空 var proNote = Notes.Elements(noteName).Attributes("No").SingleOrDefault(m => m.Value == no); if (proNote != null) { result = new XElement[] { proNote.Parent }; } } return result; } catch (Exception e) { throw e; //return false; } } //獲取記錄的條數 public int Count() { try { return Notes.Elements(noteName).Count(); } catch (Exception e) { throw e; //return false; } } //獲取所有記錄 public IEnumerable<XElement> AllNotes() { try { return Notes.Elements(noteName); } catch (Exception e) { throw e; //return false; } } //獲取最後一條記錄的No public int GetLastNoteNo() { try { if (Notes.Elements(noteName).Count() > 0) return (from Note in Notes.Elements(noteName) select Convert.ToInt32(Note.Attribute("No").Value)).Max(); else return 0; } catch (Exception e) { throw e; //return false; } } #endregion } }View Code
後面自己又用xml文件作為資料庫開發了一個WPF桌面應用程式和一個小型的網站,此時的動態鏈接庫還沒有什麼大的改進,只是對其中的代碼進行了一些優化。直到那一天,我在用ASP.NET MVC開發工作室的門戶網站(此時不再是用xml文件作為資料庫,而是用的SQL Sever),涉及到對網站後臺資料庫的訪問時,我發現了Entity Framework訪問資料庫的方便簡潔之處,首先直接在Model裡面寫一個能夠映射一張數據表的類(一般只需包含對應的屬性即可),然後使用資料庫上下文介面DbContext來輕輕鬆松訪問資料庫。先看看代碼:
Model裡面的User類:
using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web; namespace Test.Models { public class User { [Required] public Int32 Id { get; set; } [Required] [DisplayName("名字")] public String Name { get; set; } [Required] [DisplayName("用戶名")] public String Account { get; set; } [Required] [DisplayName("密碼")] public String Password { get; set; } //創建時間 [Required] public DateTime CreateTime { get; set; } //標識是否為管理員 [Required] public Boolean IsAdmin { get; set; } } }View Code
繼承了DbContext介面的類:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Entity; namespace Test.Models { public class WS_WebAppContext : DbContext { public virtual DbSet<User> Users { get; set; } public WS_WebAppContext() : base("name=WS_WebAppContext") { } } }View Code
Control裡面輕鬆訪問,只是給出了登錄驗證部分:
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Web; using System.Web.Mvc; using System.Web.Security; using Test.Models; namespace Test.Controllers { public class HomeController : Controller { WS_WebAppContext entity = new WS_WebAppContext(); //登錄頁面 public ActionResult Login() { return View(); } //檢查登錄信息 [HttpPost] public ActionResult Login(User u) { var logined = entity.Users.SingleOrDefault(m => m.Account == u.Account); if (!string.IsNullOrWhiteSpace(u.Password) && logined != null && logined.Password == u.Password) { String role = "User"; if (logined.IsAdmin) { role = "Admin"; } FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, logined.Id.ToString(), DateTime.Now, DateTime.Now.AddMinutes(120), false, role ); string encryptedTicket = FormsAuthentication.Encrypt(authTicket); HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); Response.Cookies.Add(authCookie); if (logined.IsAdmin) { return RedirectToAction("Index", "Admin");//跳轉到管理員的主頁 } else { return RedirectToAction("Index", "User");//跳轉到用戶的主頁 } } else { return Content("<script>alert('用戶名或密碼錯誤!');local.href='/Home/Index'</script>"); } } } }View Code
HomeController裡面的entity對象就是專門用來訪問資料庫的,通過它可以簡單方便的對資料庫裡面的數據表(entity.Users就對應著資料庫中的用戶表)進行增刪查改。
當我看到它的簡潔方便之處時,靈感來了,我就在想,為什麼我不用這種以對象的方式來實現那個專門用於訪問xml數據文件的動態鏈接庫呢?
對於為什麼要以對象的方式來訪問xml數據表就簡單介紹到這裡,關鍵是你要動手去開發過,你才知道這種方式的簡潔方便之處。
讓我們在(三)中接著詳談怎樣以對象的方式來訪問xml數據表。