以对象的方式来访问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 } }
后面自己又用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; } } }
继承了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") { } } }
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>"); } } } }
HomeController里面的entity对象就是专门用来访问数据库的,通过它可以简单方便的对数据库里面的数据表(entity.Users就对应着数据库中的用户表)进行增删查改。
当我看到它的简洁方便之处时,灵感来了,我就在想,为什么我不用这种以对象的方式来实现那个专门用于访问xml数据文件的动态链接库呢?
对于为什么要以对象的方式来访问xml数据表就简单介绍到这里,关键是你要动手去开发过,你才知道这种方式的简洁方便之处。
让我们在(三)中接着详谈怎样以对象的方式来访问xml数据表。